Merge "Add floating point AudioRecord read"
diff --git a/Android.mk b/Android.mk
index 70e965b..3e049f7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -152,6 +152,8 @@
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
 	core/java/android/hardware/hdmi/IHdmiDeviceEventListener.aidl \
@@ -227,8 +229,6 @@
 	core/java/android/service/dreams/IDreamManager.aidl \
 	core/java/android/service/dreams/IDreamService.aidl \
 	core/java/android/service/persistentdata/IPersistentDataBlockService.aidl \
-	core/java/android/service/fingerprint/IFingerprintService.aidl \
-	core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/service/trust/ITrustAgentService.aidl \
 	core/java/android/service/trust/ITrustAgentServiceCallback.aidl \
 	core/java/android/service/voice/IVoiceInteractionService.aidl \
@@ -267,6 +267,7 @@
 	core/java/com/android/internal/app/IBatteryStats.aidl \
 	core/java/com/android/internal/app/IProcessStats.aidl \
 	core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl \
+	core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl \
 	core/java/com/android/internal/app/IVoiceInteractor.aidl \
 	core/java/com/android/internal/app/IVoiceInteractorCallback.aidl \
 	core/java/com/android/internal/app/IVoiceInteractorRequest.aidl \
@@ -1009,6 +1010,35 @@
 
 include $(BUILD_DROIDDOC)
 
+# ==== docs for the ndk =======================
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
+LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
+LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
+LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
+LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
+LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
+LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
+LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
+# specify a second html input dir and an output path relative to OUT_DIR)
+LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl/intl /
+
+LOCAL_MODULE := ndk
+
+LOCAL_DROIDDOC_OPTIONS:= \
+		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
+		-toroot / \
+		-hdf android.whichdoc online \
+		$(sample_groups) \
+		-hdf android.hasSamples true \
+		-samplesdir $(samples_dir)
+
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-ndk
+
+include $(BUILD_DROIDDOC)
+
+
 # ==== docs that have all of the stuff that's @hidden =======================
 include $(CLEAR_VARS)
 
diff --git a/api/current.txt b/api/current.txt
index a88713e..e2ac046 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -136,8 +136,6 @@
     field public static final java.lang.String SET_WALLPAPER_HINTS = "android.permission.SET_WALLPAPER_HINTS";
     field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
-    field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
-    field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
     field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
     field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
@@ -166,37 +164,18 @@
 
   public static final class Manifest.permission_group {
     ctor public Manifest.permission_group();
-    field public static final java.lang.String ACCESSIBILITY_FEATURES = "android.permission-group.ACCESSIBILITY_FEATURES";
     field public static final java.lang.String ACCOUNTS = "android.permission-group.ACCOUNTS";
-    field public static final java.lang.String AFFECTS_BATTERY = "android.permission-group.AFFECTS_BATTERY";
-    field public static final java.lang.String APP_INFO = "android.permission-group.APP_INFO";
-    field public static final java.lang.String AUDIO_SETTINGS = "android.permission-group.AUDIO_SETTINGS";
-    field public static final java.lang.String BLUETOOTH_NETWORK = "android.permission-group.BLUETOOTH_NETWORK";
     field public static final java.lang.String BOOKMARKS = "android.permission-group.BOOKMARKS";
     field public static final java.lang.String CALENDAR = "android.permission-group.CALENDAR";
     field public static final java.lang.String CAMERA = "android.permission-group.CAMERA";
-    field public static final java.lang.String COST_MONEY = "android.permission-group.COST_MONEY";
-    field public static final java.lang.String DEVELOPMENT_TOOLS = "android.permission-group.DEVELOPMENT_TOOLS";
-    field public static final java.lang.String DEVICE_ALARMS = "android.permission-group.DEVICE_ALARMS";
-    field public static final java.lang.String DISPLAY = "android.permission-group.DISPLAY";
-    field public static final java.lang.String HARDWARE_CONTROLS = "android.permission-group.HARDWARE_CONTROLS";
+    field public static final java.lang.String CONTACTS = "android.permission-group.CONTACTS";
     field public static final java.lang.String LOCATION = "android.permission-group.LOCATION";
-    field public static final java.lang.String MESSAGES = "android.permission-group.MESSAGES";
     field public static final java.lang.String MICROPHONE = "android.permission-group.MICROPHONE";
-    field public static final java.lang.String NETWORK = "android.permission-group.NETWORK";
-    field public static final java.lang.String PERSONAL_INFO = "android.permission-group.PERSONAL_INFO";
-    field public static final java.lang.String PHONE_CALLS = "android.permission-group.PHONE_CALLS";
-    field public static final java.lang.String SCREENLOCK = "android.permission-group.SCREENLOCK";
+    field public static final java.lang.String PHONE = "android.permission-group.PHONE";
+    field public static final java.lang.String SENSORS = "android.permission-group.SENSORS";
+    field public static final java.lang.String SMS = "android.permission-group.SMS";
     field public static final java.lang.String SOCIAL_INFO = "android.permission-group.SOCIAL_INFO";
-    field public static final java.lang.String STATUS_BAR = "android.permission-group.STATUS_BAR";
-    field public static final java.lang.String STORAGE = "android.permission-group.STORAGE";
-    field public static final java.lang.String SYNC_SETTINGS = "android.permission-group.SYNC_SETTINGS";
-    field public static final java.lang.String SYSTEM_CLOCK = "android.permission-group.SYSTEM_CLOCK";
-    field public static final java.lang.String SYSTEM_TOOLS = "android.permission-group.SYSTEM_TOOLS";
     field public static final java.lang.String USER_DICTIONARY = "android.permission-group.USER_DICTIONARY";
-    field public static final java.lang.String VOICEMAIL = "android.permission-group.VOICEMAIL";
-    field public static final java.lang.String WALLPAPER = "android.permission-group.WALLPAPER";
-    field public static final java.lang.String WRITE_USER_DICTIONARY = "android.permission-group.WRITE_USER_DICTIONARY";
   }
 
   public final class R {
@@ -354,6 +333,7 @@
     field public static final int bottomRightRadius = 16843180; // 0x10101ac
     field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
     field public static final int breadCrumbTitle = 16843523; // 0x1010303
+    field public static final int breakStrategy = 16844011; // 0x10104eb
     field public static final int bufferType = 16843086; // 0x101014e
     field public static final int button = 16843015; // 0x1010107
     field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -524,6 +504,7 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
+    field public static final int durationScaleHint = 16844014; // 0x10104ee
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
@@ -1199,6 +1180,7 @@
     field public static final int summaryColumn = 16843426; // 0x10102a2
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
+    field public static final int supportsAssistGesture = 16844012; // 0x10104ec
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1299,6 +1281,7 @@
     field public static final int thicknessRatio = 16843164; // 0x101019c
     field public static final int thumb = 16843074; // 0x1010142
     field public static final int thumbOffset = 16843075; // 0x1010143
+    field public static final int thumbPosition = 16844013; // 0x10104ed
     field public static final int thumbTextPadding = 16843634; // 0x1010372
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
@@ -1694,6 +1677,8 @@
 
   public static final class R.id {
     ctor public R.id();
+    field public static final int accessibilityActionScrollToPosition = 16908342; // 0x1020036
+    field public static final int accessibilityActionShowOnScreen = 16908341; // 0x1020035
     field public static final int addToDictionary = 16908330; // 0x102002a
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
@@ -2874,6 +2859,7 @@
     method public void cancel();
     method public android.animation.Animator clone();
     method public void end();
+    method public long getDistanceBasedDuration();
     method public abstract long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
@@ -2887,12 +2873,16 @@
     method public void removePauseListener(android.animation.Animator.AnimatorPauseListener);
     method public void resume();
     method public abstract android.animation.Animator setDuration(long);
+    method public void setDurationScaleHint(int, android.content.res.Resources);
     method public abstract void setInterpolator(android.animation.TimeInterpolator);
     method public abstract void setStartDelay(long);
     method public void setTarget(java.lang.Object);
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
+    field public static final int HINT_DISTANCE_DEFINED_IN_DP = 2; // 0x2
+    field public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1; // 0x1
+    field public static final int HINT_NO_SCALE = 0; // 0x0
   }
 
   public static abstract interface Animator.AnimatorListener {
@@ -3551,6 +3541,7 @@
   public class ActivityManager {
     method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
     method public boolean clearApplicationUserData();
+    method public void clearWatchHeapLimit();
     method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
     method public android.util.Size getAppTaskThumbnailSize();
     method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
@@ -3577,6 +3568,8 @@
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    method public void setWatchHeapLimit(long);
+    field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
     field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
     field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
     field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
@@ -3968,6 +3961,48 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AssistAction {
+    method public static void updateAssistData(android.os.Bundle, android.os.Bundle);
+    field public static final java.lang.String ASSIST_ACTION_KEY = "android:assist_action";
+    field public static final java.lang.String KEY_ACTION_OBJECT = "object";
+    field public static final java.lang.String KEY_ACTION_STATUS = "actionStatus";
+    field public static final java.lang.String KEY_DESCRIPTION = "description";
+    field public static final java.lang.String KEY_ID = "@id";
+    field public static final java.lang.String KEY_NAME = "name";
+    field public static final java.lang.String KEY_TYPE = "@type";
+    field public static final java.lang.String KEY_URL = "url";
+    field public static final java.lang.String STATUS_TYPE_ACTIVE = "ActiveActionStatus";
+    field public static final java.lang.String STATUS_TYPE_COMPLETED = "CompletedActionStatus";
+    field public static final java.lang.String TYPE_ADD_ACTION = "AddAction";
+    field public static final java.lang.String TYPE_BOOKMARK_ACTION = "BookmarkAction";
+    field public static final java.lang.String TYPE_LIKE_ACTION = "LikeAction";
+    field public static final java.lang.String TYPE_LISTEN_ACTION = "ListenAction";
+    field public static final java.lang.String TYPE_VIEW_ACTION = "ViewAction";
+    field public static final java.lang.String TYPE_WANT_ACTION = "WantAction";
+    field public static final java.lang.String TYPE_WATCH_ACTION = "WatchAction";
+  }
+
+  public static final class AssistAction.ActionBuilder {
+    ctor public AssistAction.ActionBuilder();
+    method public android.os.Bundle build();
+    method public android.app.AssistAction.ActionBuilder set(java.lang.String, java.lang.String);
+    method public android.app.AssistAction.ActionBuilder set(java.lang.String, android.os.Bundle);
+    method public android.app.AssistAction.ActionBuilder setObject(android.os.Bundle);
+    method public android.app.AssistAction.ActionBuilder setType(java.lang.String);
+  }
+
+  public static final class AssistAction.ThingBuilder {
+    ctor public AssistAction.ThingBuilder();
+    method public android.os.Bundle build();
+    method public android.app.AssistAction.ThingBuilder set(java.lang.String, java.lang.String);
+    method public android.app.AssistAction.ThingBuilder set(java.lang.String, android.os.Bundle);
+    method public android.app.AssistAction.ThingBuilder setDescription(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setId(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setName(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setType(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setUrl(android.net.Uri);
+  }
+
   public class AssistContent implements android.os.Parcelable {
     ctor public AssistContent();
     method public int describeContents();
@@ -4706,6 +4741,7 @@
     field public static final java.lang.String CATEGORY_PROGRESS = "progress";
     field public static final java.lang.String CATEGORY_PROMO = "promo";
     field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final java.lang.String CATEGORY_REMINDER = "reminder";
     field public static final java.lang.String CATEGORY_SERVICE = "service";
     field public static final java.lang.String CATEGORY_SOCIAL = "social";
     field public static final java.lang.String CATEGORY_STATUS = "status";
@@ -5092,6 +5128,7 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
     field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
+    field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
     field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
     field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
     field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -5308,6 +5345,11 @@
     method public void onRejectSharedElements(java.util.List<android.view.View>);
     method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
     method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.app.SharedElementCallback.OnSharedElementsReadyListener);
+  }
+
+  public static abstract interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public abstract void onSharedElementsReady();
   }
 
   public deprecated class TabActivity extends android.app.ActivityGroup {
@@ -5431,10 +5473,12 @@
 
   public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable {
     ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence);
+    ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int);
     method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence);
     method public int countSynonyms();
     method public int describeContents();
     method public android.os.Bundle getExtras();
+    method public int getIndex();
     method public java.lang.CharSequence getLabel();
     method public java.lang.CharSequence getSynonymAt(int);
     method public void setExtras(android.os.Bundle);
@@ -5704,6 +5748,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final java.lang.String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
@@ -8006,6 +8051,7 @@
     field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
     field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
+    field public static final java.lang.String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
@@ -8106,6 +8152,8 @@
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
+    field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
+    field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
@@ -8379,6 +8427,7 @@
     ctor public RestrictionEntry(java.lang.String, boolean);
     ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
     ctor public RestrictionEntry(java.lang.String, int);
+    ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean);
     ctor public RestrictionEntry(android.os.Parcel);
     method public int describeContents();
     method public java.lang.String[] getAllSelectedStrings();
@@ -8387,6 +8436,7 @@
     method public java.lang.String getDescription();
     method public int getIntValue();
     method public java.lang.String getKey();
+    method public android.content.RestrictionEntry[] getRestrictions();
     method public boolean getSelectedState();
     method public java.lang.String getSelectedString();
     method public java.lang.String getTitle();
@@ -8398,6 +8448,7 @@
     method public void setChoiceValues(android.content.Context, int);
     method public void setDescription(java.lang.String);
     method public void setIntValue(int);
+    method public void setRestrictions(android.content.RestrictionEntry[]);
     method public void setSelectedState(boolean);
     method public void setSelectedString(java.lang.String);
     method public void setTitle(java.lang.String);
@@ -8405,6 +8456,8 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR;
     field public static final int TYPE_BOOLEAN = 1; // 0x1
+    field public static final int TYPE_BUNDLE = 7; // 0x7
+    field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8
     field public static final int TYPE_CHOICE = 2; // 0x2
     field public static final int TYPE_INTEGER = 5; // 0x5
     field public static final int TYPE_MULTI_SELECT = 4; // 0x4
@@ -8413,6 +8466,7 @@
   }
 
   public class RestrictionsManager {
+    method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>);
     method public android.content.Intent createLocalApprovalIntent();
     method public android.os.Bundle getApplicationRestrictions();
     method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
@@ -8837,25 +8891,6 @@
     field public java.lang.String targetPackage;
   }
 
-  public final class IntentFilterVerificationInfo implements android.os.Parcelable {
-    ctor public IntentFilterVerificationInfo();
-    ctor public IntentFilterVerificationInfo(java.lang.String, java.lang.String[]);
-    ctor public IntentFilterVerificationInfo(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    ctor public IntentFilterVerificationInfo(android.os.Parcel);
-    method public int describeContents();
-    method public java.lang.String[] getDomains();
-    method public java.lang.String getDomainsString();
-    method public java.lang.String getPackageName();
-    method public int getStatus();
-    method public java.lang.String getStatusString();
-    method public static java.lang.String getStatusStringFromValue(int);
-    method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void setStatus(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    method public void writeToXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
-    field public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
-  }
-
   public class LabeledIntent extends android.content.Intent {
     ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
     ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -9084,7 +9119,6 @@
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
@@ -9161,6 +9195,7 @@
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad";
+    field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
@@ -9441,11 +9476,10 @@
 
   public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
-    method public void applyTheme(android.content.res.Resources.Theme);
-    method public boolean canApplyTheme();
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
+    method public int getChangingConfigurations();
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
@@ -9726,15 +9760,13 @@
     method public void registerDataSetObserver(android.database.DataSetObserver);
     method public boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
-    field protected boolean mClosed;
-    field protected android.content.ContentResolver mContentResolver;
-    field protected deprecated java.lang.Long mCurrentRowID;
-    field protected int mPos;
-    field protected deprecated int mRowIdColumnIndex;
-    field protected deprecated java.util.HashMap<java.lang.Long, java.util.Map<java.lang.String, java.lang.Object>> mUpdatedRows;
+    field protected deprecated boolean mClosed;
+    field protected deprecated android.content.ContentResolver mContentResolver;
+    field protected deprecated int mPos;
   }
 
   protected static class AbstractCursor.SelfContentObserver extends android.database.ContentObserver {
@@ -9834,6 +9866,7 @@
     method public abstract void registerDataSetObserver(android.database.DataSetObserver);
     method public abstract deprecated boolean requery();
     method public abstract android.os.Bundle respond(android.os.Bundle);
+    method public abstract void setExtras(android.os.Bundle);
     method public abstract void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public abstract void unregisterContentObserver(android.database.ContentObserver);
     method public abstract void unregisterDataSetObserver(android.database.DataSetObserver);
@@ -9905,7 +9938,7 @@
     ctor public CursorWrapper(android.database.Cursor);
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public void deactivate();
+    method public deprecated void deactivate();
     method public byte[] getBlob(int);
     method public int getColumnCount();
     method public int getColumnIndex(java.lang.String);
@@ -9939,8 +9972,9 @@
     method public boolean moveToPrevious();
     method public void registerContentObserver(android.database.ContentObserver);
     method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public boolean requery();
+    method public deprecated boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
@@ -11381,6 +11415,7 @@
     method public int getTextWidths(java.lang.String, float[]);
     method public android.graphics.Typeface getTypeface();
     method public android.graphics.Xfermode getXfermode();
+    method public boolean hasGlyph(java.lang.String);
     method public final boolean isAntiAlias();
     method public final boolean isDither();
     method public boolean isElegantTextHeight();
@@ -13020,6 +13055,10 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_HYPERFOCAL_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INTRINSIC_CALIBRATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_ROTATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
@@ -13439,7 +13478,11 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCAL_LENGTH;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Float, java.lang.Float>> LENS_FOCUS_RANGE;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_INTRINSIC_CALIBRATION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_ROTATION;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_TRANSLATION;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
@@ -13571,6 +13614,8 @@
     method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRangesFor(android.util.Size);
     method public android.util.Size[] getHighSpeedVideoSizes();
     method public android.util.Size[] getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>);
+    method public final int[] getInputFormats();
+    method public android.util.Size[] getInputSizes(int);
     method public final int[] getOutputFormats();
     method public long getOutputMinFrameDuration(int, android.util.Size);
     method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
@@ -13578,6 +13623,7 @@
     method public android.util.Size[] getOutputSizes(int);
     method public long getOutputStallDuration(int, android.util.Size);
     method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public final int[] getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
     method public static boolean isOutputSupportedFor(java.lang.Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
@@ -14447,6 +14493,8 @@
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_DEFAULT = 1; // 0x1
+    field public static final int ENCODING_DTS = 7; // 0x7
+    field public static final int ENCODING_DTS_HD = 8; // 0x8
     field public static final int ENCODING_E_AC3 = 6; // 0x6
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
@@ -14722,6 +14770,16 @@
     field public static final int WRITE_NON_BLOCKING = 1; // 0x1
   }
 
+  public static class AudioTrack.Builder {
+    ctor public AudioTrack.Builder();
+    method public android.media.AudioTrack build() throws java.lang.UnsupportedOperationException;
+    method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
+  }
+
   public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
     method public abstract void onMarkerReached(android.media.AudioTrack);
     method public abstract void onPeriodicNotification(android.media.AudioTrack);
@@ -14885,6 +14943,7 @@
   public class ImageWriter implements java.lang.AutoCloseable {
     method public void close();
     method public android.media.Image dequeueInputImage();
+    method public int getFormat();
     method public int getMaxImages();
     method public static android.media.ImageWriter newInstance(android.view.Surface, int);
     method public void queueInputImage(android.media.Image);
@@ -14979,6 +15038,7 @@
     field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
     field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
     field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
+    field public static final int REASON_RECLAIMED = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -14994,6 +15054,7 @@
 
   public static abstract class MediaCodec.Callback {
     ctor public MediaCodec.Callback();
+    method public void onCodecReleased(android.media.MediaCodec, int);
     method public abstract void onError(android.media.MediaCodec, android.media.MediaCodec.CodecException);
     method public abstract void onInputBufferAvailable(android.media.MediaCodec, int);
     method public abstract void onOutputBufferAvailable(android.media.MediaCodec, int, android.media.MediaCodec.BufferInfo);
@@ -15259,6 +15320,7 @@
     method public static final boolean isCryptoSchemeSupported(java.util.UUID);
     method public final void release();
     method public final boolean requiresSecureDecoderComponent(java.lang.String);
+    method public final void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException;
   }
 
   public final class MediaCryptoException extends java.lang.Exception {
@@ -15314,6 +15376,8 @@
     method public void removeKeys(byte[]);
     method public void restoreKeys(byte[], byte[]);
     method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
+    method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
+    method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler);
     method public void setPropertyByteArray(java.lang.String, byte[]);
     method public void setPropertyString(java.lang.String, java.lang.String);
     field public static final int EVENT_KEY_EXPIRED = 3; // 0x3
@@ -15321,6 +15385,11 @@
     field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
     field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
     field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+    field public static final int KEY_STATUS_EXPIRED = 1; // 0x1
+    field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4
+    field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
+    field public static final int KEY_STATUS_PENDING = 3; // 0x3
+    field public static final int KEY_STATUS_USABLE = 0; // 0x0
     field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
     field public static final int KEY_TYPE_RELEASE = 3; // 0x3
     field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -15347,6 +15416,11 @@
     method public int getRequestType();
   }
 
+  public static final class MediaDrm.KeyStatus {
+    method public byte[] getKeyId();
+    method public int getStatusCode();
+  }
+
   public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
     method public java.lang.String getDiagnosticInfo();
   }
@@ -15355,6 +15429,14 @@
     method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
   }
 
+  public static abstract interface MediaDrm.OnExpirationUpdateListener {
+    method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
+  }
+
+  public static abstract interface MediaDrm.OnKeysChangeListener {
+    method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
+  }
+
   public static final class MediaDrm.ProvisionRequest {
     method public byte[] getData();
     method public java.lang.String getDefaultUrl();
@@ -15441,6 +15523,7 @@
     field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
     field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
     field public static final java.lang.String KEY_MIME = "mime";
+    field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
     field public static final java.lang.String KEY_PRIORITY = "priority";
     field public static final java.lang.String KEY_PROFILE = "profile";
     field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -15563,6 +15646,7 @@
     field public static final int METADATA_KEY_ARTIST = 2; // 0x2
     field public static final int METADATA_KEY_AUTHOR = 3; // 0x3
     field public static final int METADATA_KEY_BITRATE = 20; // 0x14
+    field public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25; // 0x19
     field public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; // 0x0
     field public static final int METADATA_KEY_COMPILATION = 15; // 0xf
     field public static final int METADATA_KEY_COMPOSER = 4; // 0x4
@@ -15961,6 +16045,24 @@
     method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
   }
 
+  public final class MediaSync {
+    ctor public MediaSync();
+    method public void configureAudioTrack(android.media.AudioTrack, int);
+    method public void configureSurface(android.view.Surface);
+    method public final android.view.Surface createInputSurface();
+    method public boolean getTimestamp(android.media.MediaTimestamp);
+    method public void queueAudio(java.nio.ByteBuffer, int, int, long);
+    method public final void release();
+    method public void setCallback(android.media.MediaSync.Callback, android.os.Handler);
+    method public void setPlaybackRate(float, int);
+    field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
+  }
+
+  public static abstract class MediaSync.Callback {
+    ctor public MediaSync.Callback();
+    method public abstract void onReturnAudioBuffer(android.media.MediaSync, java.nio.ByteBuffer, int);
+  }
+
   public class MediaSyncEvent {
     method public static android.media.MediaSyncEvent createEvent(int) throws java.lang.IllegalArgumentException;
     method public int getAudioSessionId();
@@ -15970,6 +16072,13 @@
     field public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1; // 0x1
   }
 
+  public final class MediaTimestamp {
+    ctor public MediaTimestamp();
+    field public float clockRate;
+    field public long mediaTimeUs;
+    field public long nanoTime;
+  }
+
   public final class NotProvisionedException extends android.media.MediaDrmException {
     ctor public NotProvisionedException(java.lang.String);
   }
@@ -16715,13 +16824,24 @@
 
 package android.media.midi {
 
+  public final class MidiDevice implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+    method public android.media.midi.MidiDevice.MidiConnection connectPorts(android.media.midi.MidiInputPort, int);
+    method public android.media.midi.MidiDeviceInfo getInfo();
+    method public android.media.midi.MidiInputPort openInputPort(int);
+    method public android.media.midi.MidiOutputPort openOutputPort(int);
+  }
+
+  public class MidiDevice.MidiConnection implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+  }
+
   public final class MidiDeviceInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getId();
     method public int getInputPortCount();
-    method public android.media.midi.MidiDeviceInfo.PortInfo getInputPortInfo(int);
     method public int getOutputPortCount();
-    method public android.media.midi.MidiDeviceInfo.PortInfo getOutputPortInfo(int);
+    method public android.media.midi.MidiDeviceInfo.PortInfo[] getPortList();
     method public android.os.Bundle getProperties();
     method public int getType();
     method public boolean isPrivate();
@@ -16771,6 +16891,31 @@
     method public void onReceive(byte[], int, int, long) throws java.io.IOException;
   }
 
+  public final class MidiManager {
+    method public android.media.midi.MidiDeviceInfo[] getDeviceList();
+    method public void openBluetoothDevice(android.bluetooth.BluetoothDevice, android.media.midi.MidiManager.BluetoothOpenCallback, android.os.Handler);
+    method public void openDevice(android.media.midi.MidiDeviceInfo, android.media.midi.MidiManager.DeviceOpenCallback, android.os.Handler);
+    method public void registerDeviceCallback(android.media.midi.MidiManager.DeviceCallback, android.os.Handler);
+    method public void unregisterDeviceCallback(android.media.midi.MidiManager.DeviceCallback);
+  }
+
+  public static abstract class MidiManager.BluetoothOpenCallback {
+    ctor public MidiManager.BluetoothOpenCallback();
+    method public abstract void onDeviceOpened(android.bluetooth.BluetoothDevice, android.media.midi.MidiDevice);
+  }
+
+  public static class MidiManager.DeviceCallback {
+    ctor public MidiManager.DeviceCallback();
+    method public void onDeviceAdded(android.media.midi.MidiDeviceInfo);
+    method public void onDeviceRemoved(android.media.midi.MidiDeviceInfo);
+    method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
+  }
+
+  public static abstract class MidiManager.DeviceOpenCallback {
+    ctor public MidiManager.DeviceOpenCallback();
+    method public abstract void onDeviceOpened(android.media.midi.MidiDeviceInfo, android.media.midi.MidiDevice);
+  }
+
   public final class MidiOutputPort extends android.media.midi.MidiSender implements java.io.Closeable {
     method public void close() throws java.io.IOException;
     method public void connect(android.media.midi.MidiReceiver);
@@ -16780,6 +16925,7 @@
 
   public abstract class MidiReceiver {
     ctor public MidiReceiver();
+    method public void flush() throws java.io.IOException;
     method public int getMaxMessageSize();
     method public abstract void onReceive(byte[], int, int, long) throws java.io.IOException;
     method public void send(byte[], int, int) throws java.io.IOException;
@@ -17461,6 +17607,12 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+    field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
+    field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
+    field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
+    field public static final int TIME_SHIFT_STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1; // 0x1
+    field public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 4; // 0x4
     field public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3; // 0x3
     field public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1; // 0x1
     field public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0; // 0x0
@@ -17495,6 +17647,7 @@
     method public void notifyChannelRetuned(android.net.Uri);
     method public void notifyContentAllowed();
     method public void notifyContentBlocked(android.media.tv.TvContentRating);
+    method public void notifyTimeShiftStatusChanged(int);
     method public void notifyTrackSelected(int, java.lang.String);
     method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
     method public void notifyVideoAvailable();
@@ -17511,6 +17664,12 @@
     method public abstract void onSetStreamVolume(float);
     method public abstract boolean onSetSurface(android.view.Surface);
     method public void onSurfaceChanged(int, int, int);
+    method public long onTimeShiftGetCurrentPosition();
+    method public long onTimeShiftGetStartPosition();
+    method public void onTimeShiftPause();
+    method public void onTimeShiftResume();
+    method public void onTimeShiftSeekTo(long);
+    method public void onTimeShiftSetPlaybackRate(float, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public abstract boolean onTune(android.net.Uri);
@@ -17565,6 +17724,11 @@
     method public void setCaptionEnabled(boolean);
     method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
     method public void setStreamVolume(float);
+    method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
+    method public void timeShiftPause();
+    method public void timeShiftResume();
+    method public void timeShiftSeekTo(long);
+    method public void timeShiftSetPlaybackRate(float, int);
     method public void tune(java.lang.String, android.net.Uri);
   }
 
@@ -17572,6 +17736,12 @@
     method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
   }
 
+  public static abstract class TvView.TimeShiftPositionCallback {
+    ctor public TvView.TimeShiftPositionCallback();
+    method public void onTimeShiftCurrentPositionChanged(java.lang.String, long);
+    method public void onTimeShiftStartPositionChanged(java.lang.String, long);
+  }
+
   public static abstract class TvView.TvInputCallback {
     ctor public TvView.TvInputCallback();
     method public void onChannelRetuned(java.lang.String, android.net.Uri);
@@ -17579,6 +17749,7 @@
     method public void onContentAllowed(java.lang.String);
     method public void onContentBlocked(java.lang.String, android.media.tv.TvContentRating);
     method public void onDisconnected(java.lang.String);
+    method public void onTimeShiftStatusChanged(java.lang.String, int);
     method public void onTrackSelected(java.lang.String, int, java.lang.String);
     method public void onTracksChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>);
     method public void onVideoAvailable(java.lang.String);
@@ -18798,6 +18969,7 @@
 
   public static final class WifiEnterpriseConfig.Eap {
     field public static final int AKA = 5; // 0x5
+    field public static final int AKA_PRIME = 6; // 0x6
     field public static final int NONE = -1; // 0xffffffff
     field public static final int PEAP = 0; // 0x0
     field public static final int PWD = 3; // 0x3
@@ -22159,6 +22331,9 @@
   public class BatteryManager {
     method public int getIntProperty(int);
     method public long getLongProperty(int);
+    method public boolean isCharging();
+    field public static final java.lang.String ACTION_CHARGING = "android.os.action.CHARGING";
+    field public static final java.lang.String ACTION_DISCHARGING = "android.os.action.DISCHARGING";
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
     field public static final int BATTERY_HEALTH_DEAD = 4; // 0x4
     field public static final int BATTERY_HEALTH_GOOD = 2; // 0x2
@@ -23197,6 +23372,7 @@
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
+    method public long getUserCreationTime(int);
     method public android.os.UserHandle getUserForSerialNumber(long);
     method public java.lang.String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
@@ -24052,8 +24228,16 @@
     field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
     field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
     field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
+    field public static final java.lang.String ACTION_VOICE_CANCEL_ALARM = "android.intent.action.VOICE_CANCEL_ALARM";
+    field public static final java.lang.String ACTION_VOICE_DELETE_ALARM = "android.intent.action.VOICE_DELETE_ALARM";
+    field public static final java.lang.String ALARM_SEARCH_MODE_ALL = "all";
+    field public static final java.lang.String ALARM_SEARCH_MODE_NEXT = "next";
+    field public static final java.lang.String ALARM_SEARCH_MODE_NONE = "none";
+    field public static final java.lang.String ALARM_SEARCH_MODE_TIME = "time";
+    field public static final java.lang.String EXTRA_ALARM_SEARCH_MODE = "android.intent.extra.alarm.ALARM_SEARCH_MODE";
     field public static final java.lang.String EXTRA_DAYS = "android.intent.extra.alarm.DAYS";
     field public static final java.lang.String EXTRA_HOUR = "android.intent.extra.alarm.HOUR";
+    field public static final java.lang.String EXTRA_IS_PM = "android.intent.extra.alarm.IS_PM";
     field public static final java.lang.String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH";
     field public static final java.lang.String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
     field public static final java.lang.String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES";
@@ -25732,6 +25916,8 @@
     method public static java.lang.String getVersion(android.content.Context);
     field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
+    field public static final java.lang.String ACTION_STILL_IMAGE_CAMERA_COOLDOWN = "android.media.action.STILL_IMAGE_CAMERA_COOLDOWN";
+    field public static final java.lang.String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM";
     field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
     field public static final java.lang.String AUTHORITY = "media";
     field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
@@ -26103,6 +26289,8 @@
     field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
     field public static final java.lang.String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
+    field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
+    field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
     field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
@@ -26111,6 +26299,9 @@
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
     field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
+    field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
+    field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
   }
 
@@ -26727,7 +26918,6 @@
 
   public static final class VoicemailContract.Status implements android.provider.BaseColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
     field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
     field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
     field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -26751,9 +26941,6 @@
 
   public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
     method public static android.net.Uri buildSourceUri(java.lang.String);
-    method public static int deleteAll(android.content.Context);
-    method public static android.net.Uri insert(android.content.Context, android.telecom.Voicemail);
-    method public static int insert(android.content.Context, java.util.List<android.telecom.Voicemail>);
     field public static final android.net.Uri CONTENT_URI;
     field public static final java.lang.String DATE = "date";
     field public static final java.lang.String DELETED = "deleted";
@@ -27504,6 +27691,41 @@
     method public android.renderscript.ScriptGroup create();
   }
 
+  public class ScriptGroup2 extends android.renderscript.BaseObj {
+    ctor public ScriptGroup2(long, android.renderscript.RenderScript);
+    method public java.lang.Object[] execute(java.lang.Object...);
+  }
+
+  public static final class ScriptGroup2.Binding {
+    ctor public ScriptGroup2.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+    method public android.renderscript.Script.FieldID getField();
+    method public java.lang.Object getValue();
+  }
+
+  public static final class ScriptGroup2.Builder {
+    ctor public ScriptGroup2.Builder(android.renderscript.RenderScript);
+    method public android.renderscript.ScriptGroup2.UnboundValue addInput();
+    method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
+    method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
+    method public android.renderscript.ScriptGroup2 create(java.lang.String, android.renderscript.ScriptGroup2.Future...);
+  }
+
+  public static class ScriptGroup2.Closure extends android.renderscript.BaseObj {
+    ctor public ScriptGroup2.Closure(long, android.renderscript.RenderScript);
+    ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    method public android.renderscript.ScriptGroup2.Future getGlobal(android.renderscript.Script.FieldID);
+    method public android.renderscript.ScriptGroup2.Future getReturn();
+  }
+
+  public static class ScriptGroup2.Future {
+  }
+
+  public static class ScriptGroup2.UnboundValue {
+  }
+
   public abstract class ScriptIntrinsic extends android.renderscript.Script {
   }
 
@@ -28009,6 +28231,7 @@
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
+    field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
@@ -28130,6 +28353,7 @@
     method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
+    field public static final int START_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int START_WITH_ASSIST = 1; // 0x1
     field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
@@ -28138,6 +28362,7 @@
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
     method public void finish();
+    method public android.content.Context getContext();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
     method public void hide();
@@ -29174,22 +29399,6 @@
 
 package android.telecom {
 
-  public class AuthenticatorService extends android.app.Service {
-    ctor public AuthenticatorService();
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
-  public class AuthenticatorService.Authenticator extends android.accounts.AbstractAccountAuthenticator {
-    ctor public AuthenticatorService.Authenticator(android.content.Context);
-    method public android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
-    method public android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-    method public java.lang.String getAuthTokenLabel(java.lang.String);
-    method public android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
-    method public android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
-  }
-
   public class PhoneAccount implements android.os.Parcelable {
     method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
     method public android.graphics.drawable.Drawable createIconDrawable(android.content.Context);
@@ -29301,36 +29510,6 @@
     field public static final int TX_ENABLED = 1; // 0x1
   }
 
-  public class Voicemail implements android.os.Parcelable {
-    method public static android.telecom.Voicemail.Builder createForInsertion(long, java.lang.String);
-    method public static android.telecom.Voicemail.Builder createForUpdate(long, java.lang.String);
-    method public int describeContents();
-    method public long getDuration();
-    method public long getId();
-    method public java.lang.String getNumber();
-    method public java.lang.String getSourceData();
-    method public java.lang.String getSourcePackage();
-    method public long getTimestampMillis();
-    method public android.net.Uri getUri();
-    method public boolean hasContent();
-    method public boolean isRead();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.telecom.Voicemail> CREATOR;
-  }
-
-  public static class Voicemail.Builder {
-    method public android.telecom.Voicemail build();
-    method public android.telecom.Voicemail.Builder setDuration(long);
-    method public android.telecom.Voicemail.Builder setHasContent(boolean);
-    method public android.telecom.Voicemail.Builder setId(long);
-    method public android.telecom.Voicemail.Builder setIsRead(boolean);
-    method public android.telecom.Voicemail.Builder setNumber(java.lang.String);
-    method public android.telecom.Voicemail.Builder setSourceData(java.lang.String);
-    method public android.telecom.Voicemail.Builder setSourcePackage(java.lang.String);
-    method public android.telecom.Voicemail.Builder setTimestamp(long);
-    method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
-  }
-
 }
 
 package android.telephony {
@@ -30434,7 +30613,7 @@
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public void deactivate();
+    method public deprecated void deactivate();
     method public byte[] getBlob(int);
     method public int getColumnCount();
     method public int getColumnIndex(java.lang.String);
@@ -30467,8 +30646,9 @@
     method public boolean moveToPrevious();
     method public void registerContentObserver(android.database.ContentObserver);
     method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public boolean requery();
+    method public deprecated boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
@@ -30500,6 +30680,7 @@
     method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
     method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
     method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
     method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -30512,12 +30693,12 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public java.lang.String getDefaultBrowserPackageName(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
@@ -30560,6 +30741,7 @@
     method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void verifyPendingInstall(int, int);
   }
@@ -30882,6 +31064,9 @@
     method public final void increaseWidthTo(int);
     method public boolean isRtlCharAt(int);
     method protected final boolean isSpanned();
+    field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+    field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+    field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
     field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
     field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
   }
@@ -32413,6 +32598,7 @@
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
     method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
+    method public static void endTransitions(android.view.ViewGroup);
     method public static void go(android.transition.Scene);
     method public static void go(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Transition);
@@ -33431,10 +33617,10 @@
     method public java.lang.String getName();
     method public int getProductId();
     method public int getSources();
-    method public java.lang.String getUniqueId();
     method public int getVendorId();
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
+    method public boolean hasMic();
     method public boolean isVirtual();
     method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -34520,6 +34706,7 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void dispatchProvideAssistStructure(android.view.ViewAssistStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -34776,7 +34963,8 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onProvideAssistStructure(android.view.ViewAssistStructure, android.os.Bundle);
+    method public void onProvideAssistStructure(android.view.ViewAssistStructure);
+    method public void onProvideVirtualAssistStructure(android.view.ViewAssistStructure);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -35186,14 +35374,36 @@
 
   public abstract class ViewAssistStructure {
     ctor public ViewAssistStructure();
+    method public abstract void asyncCommit();
+    method public abstract android.view.ViewAssistStructure asyncNewChild(int);
+    method public abstract void clearExtras();
+    method public abstract android.os.Bundle editExtras();
+    method public abstract int getChildCount();
     method public abstract java.lang.CharSequence getHint();
     method public abstract java.lang.CharSequence getText();
     method public abstract int getTextSelectionEnd();
     method public abstract int getTextSelectionStart();
+    method public abstract android.view.ViewAssistStructure newChild(int);
+    method public abstract void setAccessibilityFocused(boolean);
+    method public abstract void setActivated(boolean);
+    method public abstract void setCheckable(boolean);
+    method public abstract void setChecked(boolean);
+    method public abstract void setChildCount(int);
+    method public abstract void setClassName(java.lang.String);
+    method public abstract void setClickable(boolean);
+    method public abstract void setContentDescription(java.lang.CharSequence);
+    method public abstract void setDimens(int, int, int, int, int, int);
+    method public abstract void setEnabled(boolean);
+    method public abstract void setFocusable(boolean);
+    method public abstract void setFocused(boolean);
     method public abstract void setHint(java.lang.CharSequence);
+    method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+    method public abstract void setLongClickable(boolean);
+    method public abstract void setSelected(boolean);
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextPaint(android.text.TextPaint);
+    method public abstract void setVisibility(int);
   }
 
   public class ViewConfiguration {
@@ -36223,9 +36433,11 @@
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
     field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
@@ -36283,6 +36495,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_BACKWARD;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_FORWARD;
+    field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_TO_POSITION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
@@ -40044,6 +40257,7 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
     method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
@@ -40145,6 +40359,7 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
     method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
diff --git a/api/removed.txt b/api/removed.txt
index c2b9d3e..0c433c3 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -6,6 +6,16 @@
 
 }
 
+package android.database {
+
+  public abstract class AbstractCursor implements android.database.CrossProcessCursor {
+    field protected java.lang.Long mCurrentRowID;
+    field protected int mRowIdColumnIndex;
+    field protected java.util.HashMap<java.lang.Long, java.util.Map<java.lang.String, java.lang.Object>> mUpdatedRows;
+  }
+
+}
+
 package android.media {
 
   public class AudioFormat {
diff --git a/api/system-current.txt b/api/system-current.txt
index b82e9b8..162a37c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -135,6 +135,7 @@
     field public static final java.lang.String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
     field public static final java.lang.String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
     field public static final java.lang.String PERFORM_CDMA_PROVISIONING = "android.permission.PERFORM_CDMA_PROVISIONING";
+    field public static final java.lang.String PERFORM_SIM_ACTIVATION = "android.permission.PERFORM_SIM_ACTIVATION";
     field public static final deprecated java.lang.String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
     field public static final java.lang.String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
     field public static final java.lang.String PROVIDE_TRUST_AGENT = "android.permission.PROVIDE_TRUST_AGENT";
@@ -201,8 +202,6 @@
     field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
     field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
-    field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
-    field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
     field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
     field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
@@ -237,37 +236,18 @@
 
   public static final class Manifest.permission_group {
     ctor public Manifest.permission_group();
-    field public static final java.lang.String ACCESSIBILITY_FEATURES = "android.permission-group.ACCESSIBILITY_FEATURES";
     field public static final java.lang.String ACCOUNTS = "android.permission-group.ACCOUNTS";
-    field public static final java.lang.String AFFECTS_BATTERY = "android.permission-group.AFFECTS_BATTERY";
-    field public static final java.lang.String APP_INFO = "android.permission-group.APP_INFO";
-    field public static final java.lang.String AUDIO_SETTINGS = "android.permission-group.AUDIO_SETTINGS";
-    field public static final java.lang.String BLUETOOTH_NETWORK = "android.permission-group.BLUETOOTH_NETWORK";
     field public static final java.lang.String BOOKMARKS = "android.permission-group.BOOKMARKS";
     field public static final java.lang.String CALENDAR = "android.permission-group.CALENDAR";
     field public static final java.lang.String CAMERA = "android.permission-group.CAMERA";
-    field public static final java.lang.String COST_MONEY = "android.permission-group.COST_MONEY";
-    field public static final java.lang.String DEVELOPMENT_TOOLS = "android.permission-group.DEVELOPMENT_TOOLS";
-    field public static final java.lang.String DEVICE_ALARMS = "android.permission-group.DEVICE_ALARMS";
-    field public static final java.lang.String DISPLAY = "android.permission-group.DISPLAY";
-    field public static final java.lang.String HARDWARE_CONTROLS = "android.permission-group.HARDWARE_CONTROLS";
+    field public static final java.lang.String CONTACTS = "android.permission-group.CONTACTS";
     field public static final java.lang.String LOCATION = "android.permission-group.LOCATION";
-    field public static final java.lang.String MESSAGES = "android.permission-group.MESSAGES";
     field public static final java.lang.String MICROPHONE = "android.permission-group.MICROPHONE";
-    field public static final java.lang.String NETWORK = "android.permission-group.NETWORK";
-    field public static final java.lang.String PERSONAL_INFO = "android.permission-group.PERSONAL_INFO";
-    field public static final java.lang.String PHONE_CALLS = "android.permission-group.PHONE_CALLS";
-    field public static final java.lang.String SCREENLOCK = "android.permission-group.SCREENLOCK";
+    field public static final java.lang.String PHONE = "android.permission-group.PHONE";
+    field public static final java.lang.String SENSORS = "android.permission-group.SENSORS";
+    field public static final java.lang.String SMS = "android.permission-group.SMS";
     field public static final java.lang.String SOCIAL_INFO = "android.permission-group.SOCIAL_INFO";
-    field public static final java.lang.String STATUS_BAR = "android.permission-group.STATUS_BAR";
-    field public static final java.lang.String STORAGE = "android.permission-group.STORAGE";
-    field public static final java.lang.String SYNC_SETTINGS = "android.permission-group.SYNC_SETTINGS";
-    field public static final java.lang.String SYSTEM_CLOCK = "android.permission-group.SYSTEM_CLOCK";
-    field public static final java.lang.String SYSTEM_TOOLS = "android.permission-group.SYSTEM_TOOLS";
     field public static final java.lang.String USER_DICTIONARY = "android.permission-group.USER_DICTIONARY";
-    field public static final java.lang.String VOICEMAIL = "android.permission-group.VOICEMAIL";
-    field public static final java.lang.String WALLPAPER = "android.permission-group.WALLPAPER";
-    field public static final java.lang.String WRITE_USER_DICTIONARY = "android.permission-group.WRITE_USER_DICTIONARY";
   }
 
   public final class R {
@@ -426,6 +406,7 @@
     field public static final int bottomRightRadius = 16843180; // 0x10101ac
     field public static final int breadCrumbShortTitle = 16843524; // 0x1010304
     field public static final int breadCrumbTitle = 16843523; // 0x1010303
+    field public static final int breakStrategy = 16844011; // 0x10104eb
     field public static final int bufferType = 16843086; // 0x101014e
     field public static final int button = 16843015; // 0x1010107
     field public static final int buttonBarButtonStyle = 16843567; // 0x101032f
@@ -596,6 +577,7 @@
     field public static final int dropDownWidth = 16843362; // 0x1010262
     field public static final int duplicateParentState = 16842985; // 0x10100e9
     field public static final int duration = 16843160; // 0x1010198
+    field public static final int durationScaleHint = 16844014; // 0x10104ee
     field public static final int editTextBackground = 16843602; // 0x1010352
     field public static final int editTextColor = 16843601; // 0x1010351
     field public static final int editTextPreferenceStyle = 16842898; // 0x1010092
@@ -1275,6 +1257,7 @@
     field public static final int summaryColumn = 16843426; // 0x10102a2
     field public static final int summaryOff = 16843248; // 0x10101f0
     field public static final int summaryOn = 16843247; // 0x10101ef
+    field public static final int supportsAssistGesture = 16844012; // 0x10104ec
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1375,6 +1358,7 @@
     field public static final int thicknessRatio = 16843164; // 0x101019c
     field public static final int thumb = 16843074; // 0x1010142
     field public static final int thumbOffset = 16843075; // 0x1010143
+    field public static final int thumbPosition = 16844013; // 0x10104ed
     field public static final int thumbTextPadding = 16843634; // 0x1010372
     field public static final int thumbTint = 16843889; // 0x1010471
     field public static final int thumbTintMode = 16843890; // 0x1010472
@@ -1770,6 +1754,8 @@
 
   public static final class R.id {
     ctor public R.id();
+    field public static final int accessibilityActionScrollToPosition = 16908342; // 0x1020036
+    field public static final int accessibilityActionShowOnScreen = 16908341; // 0x1020035
     field public static final int addToDictionary = 16908330; // 0x102002a
     field public static final int background = 16908288; // 0x1020000
     field public static final int button1 = 16908313; // 0x1020019
@@ -2953,6 +2939,7 @@
     method public void cancel();
     method public android.animation.Animator clone();
     method public void end();
+    method public long getDistanceBasedDuration();
     method public abstract long getDuration();
     method public android.animation.TimeInterpolator getInterpolator();
     method public java.util.ArrayList<android.animation.Animator.AnimatorListener> getListeners();
@@ -2966,12 +2953,16 @@
     method public void removePauseListener(android.animation.Animator.AnimatorPauseListener);
     method public void resume();
     method public abstract android.animation.Animator setDuration(long);
+    method public void setDurationScaleHint(int, android.content.res.Resources);
     method public abstract void setInterpolator(android.animation.TimeInterpolator);
     method public abstract void setStartDelay(long);
     method public void setTarget(java.lang.Object);
     method public void setupEndValues();
     method public void setupStartValues();
     method public void start();
+    field public static final int HINT_DISTANCE_DEFINED_IN_DP = 2; // 0x2
+    field public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1; // 0x1
+    field public static final int HINT_NO_SCALE = 0; // 0x0
   }
 
   public static abstract interface Animator.AnimatorListener {
@@ -3638,6 +3629,7 @@
   public class ActivityManager {
     method public int addAppTask(android.app.Activity, android.content.Intent, android.app.ActivityManager.TaskDescription, android.graphics.Bitmap);
     method public boolean clearApplicationUserData();
+    method public void clearWatchHeapLimit();
     method public void dumpPackageState(java.io.FileDescriptor, java.lang.String);
     method public android.util.Size getAppTaskThumbnailSize();
     method public java.util.List<android.app.ActivityManager.AppTask> getAppTasks();
@@ -3665,6 +3657,8 @@
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
+    method public void setWatchHeapLimit(long);
+    field public static final java.lang.String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
     field public static final int LOCK_TASK_MODE_LOCKED = 1; // 0x1
     field public static final int LOCK_TASK_MODE_NONE = 0; // 0x0
     field public static final int LOCK_TASK_MODE_PINNED = 2; // 0x2
@@ -4058,6 +4052,48 @@
     field public java.lang.String serviceDetails;
   }
 
+  public final class AssistAction {
+    method public static void updateAssistData(android.os.Bundle, android.os.Bundle);
+    field public static final java.lang.String ASSIST_ACTION_KEY = "android:assist_action";
+    field public static final java.lang.String KEY_ACTION_OBJECT = "object";
+    field public static final java.lang.String KEY_ACTION_STATUS = "actionStatus";
+    field public static final java.lang.String KEY_DESCRIPTION = "description";
+    field public static final java.lang.String KEY_ID = "@id";
+    field public static final java.lang.String KEY_NAME = "name";
+    field public static final java.lang.String KEY_TYPE = "@type";
+    field public static final java.lang.String KEY_URL = "url";
+    field public static final java.lang.String STATUS_TYPE_ACTIVE = "ActiveActionStatus";
+    field public static final java.lang.String STATUS_TYPE_COMPLETED = "CompletedActionStatus";
+    field public static final java.lang.String TYPE_ADD_ACTION = "AddAction";
+    field public static final java.lang.String TYPE_BOOKMARK_ACTION = "BookmarkAction";
+    field public static final java.lang.String TYPE_LIKE_ACTION = "LikeAction";
+    field public static final java.lang.String TYPE_LISTEN_ACTION = "ListenAction";
+    field public static final java.lang.String TYPE_VIEW_ACTION = "ViewAction";
+    field public static final java.lang.String TYPE_WANT_ACTION = "WantAction";
+    field public static final java.lang.String TYPE_WATCH_ACTION = "WatchAction";
+  }
+
+  public static final class AssistAction.ActionBuilder {
+    ctor public AssistAction.ActionBuilder();
+    method public android.os.Bundle build();
+    method public android.app.AssistAction.ActionBuilder set(java.lang.String, java.lang.String);
+    method public android.app.AssistAction.ActionBuilder set(java.lang.String, android.os.Bundle);
+    method public android.app.AssistAction.ActionBuilder setObject(android.os.Bundle);
+    method public android.app.AssistAction.ActionBuilder setType(java.lang.String);
+  }
+
+  public static final class AssistAction.ThingBuilder {
+    ctor public AssistAction.ThingBuilder();
+    method public android.os.Bundle build();
+    method public android.app.AssistAction.ThingBuilder set(java.lang.String, java.lang.String);
+    method public android.app.AssistAction.ThingBuilder set(java.lang.String, android.os.Bundle);
+    method public android.app.AssistAction.ThingBuilder setDescription(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setId(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setName(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setType(java.lang.String);
+    method public android.app.AssistAction.ThingBuilder setUrl(android.net.Uri);
+  }
+
   public class AssistContent implements android.os.Parcelable {
     ctor public AssistContent();
     method public int describeContents();
@@ -4796,6 +4832,7 @@
     field public static final java.lang.String CATEGORY_PROGRESS = "progress";
     field public static final java.lang.String CATEGORY_PROMO = "promo";
     field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
+    field public static final java.lang.String CATEGORY_REMINDER = "reminder";
     field public static final java.lang.String CATEGORY_SERVICE = "service";
     field public static final java.lang.String CATEGORY_SOCIAL = "social";
     field public static final java.lang.String CATEGORY_STATUS = "status";
@@ -5182,6 +5219,7 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR;
     field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000
+    field public static final int FLAG_IMMUTABLE = 67108864; // 0x4000000
     field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000
     field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000
     field public static final int FLAG_UPDATE_CURRENT = 134217728; // 0x8000000
@@ -5398,6 +5436,11 @@
     method public void onRejectSharedElements(java.util.List<android.view.View>);
     method public void onSharedElementEnd(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
     method public void onSharedElementStart(java.util.List<java.lang.String>, java.util.List<android.view.View>, java.util.List<android.view.View>);
+    method public void onSharedElementsArrived(java.util.List<java.lang.String>, java.util.List<android.view.View>, android.app.SharedElementCallback.OnSharedElementsReadyListener);
+  }
+
+  public static abstract interface SharedElementCallback.OnSharedElementsReadyListener {
+    method public abstract void onSharedElementsReady();
   }
 
   public deprecated class TabActivity extends android.app.ActivityGroup {
@@ -5521,10 +5564,12 @@
 
   public static final class VoiceInteractor.PickOptionRequest.Option implements android.os.Parcelable {
     ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence);
+    ctor public VoiceInteractor.PickOptionRequest.Option(java.lang.CharSequence, int);
     method public android.app.VoiceInteractor.PickOptionRequest.Option addSynonym(java.lang.CharSequence);
     method public int countSynonyms();
     method public int describeContents();
     method public android.os.Bundle getExtras();
+    method public int getIndex();
     method public java.lang.CharSequence getLabel();
     method public java.lang.CharSequence getSynonymAt(int);
     method public void setExtras(android.os.Bundle);
@@ -5686,6 +5731,7 @@
     method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
     method public int getCurrentFailedPasswordAttempts();
     method public java.lang.String getDeviceInitializerApp();
+    method public android.content.ComponentName getDeviceInitializerComponent();
     method public java.lang.String getDeviceOwner();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5808,6 +5854,7 @@
     field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
     field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME";
+    field public static final java.lang.String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS";
     field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
     field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE";
     field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN";
@@ -5901,6 +5948,7 @@
     method public android.app.backup.RestoreSession beginRestoreSession();
     method public void dataChanged();
     method public static void dataChanged(java.lang.String);
+    method public long getAvailableRestoreToken(java.lang.String);
     method public java.lang.String getCurrentTransport();
     method public boolean isBackupEnabled();
     method public java.lang.String[] listAllTransports();
@@ -6331,6 +6379,7 @@
     method public android.bluetooth.BluetoothDevice getRemoteDevice(byte[]);
     method public int getScanMode();
     method public int getState();
+    method public boolean isBleScanAlwaysAvailable();
     method public boolean isDiscovering();
     method public boolean isEnabled();
     method public boolean isMultipleAdvertisementSupported();
@@ -6347,6 +6396,7 @@
     field public static final java.lang.String ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
     field public static final java.lang.String ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
     field public static final java.lang.String ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+    field public static final java.lang.String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE = "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
     field public static final java.lang.String ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
     field public static final java.lang.String ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
     field public static final java.lang.String ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
@@ -8222,6 +8272,7 @@
     field public static final java.lang.String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
     field public static final java.lang.String ACTION_POWER_DISCONNECTED = "android.intent.action.ACTION_POWER_DISCONNECTED";
     field public static final java.lang.String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
+    field public static final java.lang.String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
     field public static final java.lang.String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
     field public static final java.lang.String ACTION_QUERY_PACKAGE_RESTART = "android.intent.action.QUERY_PACKAGE_RESTART";
     field public static final java.lang.String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
@@ -8327,6 +8378,8 @@
     field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
+    field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
+    field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
@@ -8600,6 +8653,7 @@
     ctor public RestrictionEntry(java.lang.String, boolean);
     ctor public RestrictionEntry(java.lang.String, java.lang.String[]);
     ctor public RestrictionEntry(java.lang.String, int);
+    ctor public RestrictionEntry(java.lang.String, android.content.RestrictionEntry[], boolean);
     ctor public RestrictionEntry(android.os.Parcel);
     method public int describeContents();
     method public java.lang.String[] getAllSelectedStrings();
@@ -8608,6 +8662,7 @@
     method public java.lang.String getDescription();
     method public int getIntValue();
     method public java.lang.String getKey();
+    method public android.content.RestrictionEntry[] getRestrictions();
     method public boolean getSelectedState();
     method public java.lang.String getSelectedString();
     method public java.lang.String getTitle();
@@ -8619,6 +8674,7 @@
     method public void setChoiceValues(android.content.Context, int);
     method public void setDescription(java.lang.String);
     method public void setIntValue(int);
+    method public void setRestrictions(android.content.RestrictionEntry[]);
     method public void setSelectedState(boolean);
     method public void setSelectedString(java.lang.String);
     method public void setTitle(java.lang.String);
@@ -8626,6 +8682,8 @@
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR;
     field public static final int TYPE_BOOLEAN = 1; // 0x1
+    field public static final int TYPE_BUNDLE = 7; // 0x7
+    field public static final int TYPE_BUNDLE_ARRAY = 8; // 0x8
     field public static final int TYPE_CHOICE = 2; // 0x2
     field public static final int TYPE_INTEGER = 5; // 0x5
     field public static final int TYPE_MULTI_SELECT = 4; // 0x4
@@ -8634,6 +8692,7 @@
   }
 
   public class RestrictionsManager {
+    method public static android.os.Bundle convertRestrictionsToBundle(java.util.List<android.content.RestrictionEntry>);
     method public android.content.Intent createLocalApprovalIntent();
     method public android.os.Bundle getApplicationRestrictions();
     method public java.util.List<android.content.RestrictionEntry> getManifestRestrictions(java.lang.String);
@@ -9077,25 +9136,6 @@
     field public java.lang.String targetPackage;
   }
 
-  public final class IntentFilterVerificationInfo implements android.os.Parcelable {
-    ctor public IntentFilterVerificationInfo();
-    ctor public IntentFilterVerificationInfo(java.lang.String, java.lang.String[]);
-    ctor public IntentFilterVerificationInfo(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    ctor public IntentFilterVerificationInfo(android.os.Parcel);
-    method public int describeContents();
-    method public java.lang.String[] getDomains();
-    method public java.lang.String getDomainsString();
-    method public java.lang.String getPackageName();
-    method public int getStatus();
-    method public java.lang.String getStatusString();
-    method public static java.lang.String getStatusStringFromValue(int);
-    method public void readFromXml(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
-    method public void setStatus(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    method public void writeToXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
-    field public static final android.os.Parcelable.Creator<android.content.pm.IntentFilterVerificationInfo> CREATOR;
-  }
-
   public class LabeledIntent extends android.content.Intent {
     ctor public LabeledIntent(android.content.Intent, java.lang.String, int, int);
     ctor public LabeledIntent(android.content.Intent, java.lang.String, java.lang.CharSequence, int);
@@ -9330,7 +9370,6 @@
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public abstract java.lang.String getNameForUid(int);
@@ -9412,6 +9451,7 @@
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad";
+    field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
     field public static final java.lang.String FEATURE_INPUT_METHODS = "android.software.input_methods";
     field public static final java.lang.String FEATURE_LEANBACK = "android.software.leanback";
@@ -9727,11 +9767,10 @@
 
   public class ColorStateList implements android.os.Parcelable {
     ctor public ColorStateList(int[][], int[]);
-    method public void applyTheme(android.content.res.Resources.Theme);
-    method public boolean canApplyTheme();
     method public static deprecated android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static android.content.res.ColorStateList createFromXml(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public int describeContents();
+    method public int getChangingConfigurations();
     method public int getColorForState(int[], int);
     method public int getDefaultColor();
     method public boolean isOpaque();
@@ -10012,15 +10051,13 @@
     method public void registerDataSetObserver(android.database.DataSetObserver);
     method public boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
-    field protected boolean mClosed;
-    field protected android.content.ContentResolver mContentResolver;
-    field protected deprecated java.lang.Long mCurrentRowID;
-    field protected int mPos;
-    field protected deprecated int mRowIdColumnIndex;
-    field protected deprecated java.util.HashMap<java.lang.Long, java.util.Map<java.lang.String, java.lang.Object>> mUpdatedRows;
+    field protected deprecated boolean mClosed;
+    field protected deprecated android.content.ContentResolver mContentResolver;
+    field protected deprecated int mPos;
   }
 
   protected static class AbstractCursor.SelfContentObserver extends android.database.ContentObserver {
@@ -10120,6 +10157,7 @@
     method public abstract void registerDataSetObserver(android.database.DataSetObserver);
     method public abstract deprecated boolean requery();
     method public abstract android.os.Bundle respond(android.os.Bundle);
+    method public abstract void setExtras(android.os.Bundle);
     method public abstract void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public abstract void unregisterContentObserver(android.database.ContentObserver);
     method public abstract void unregisterDataSetObserver(android.database.DataSetObserver);
@@ -10191,7 +10229,7 @@
     ctor public CursorWrapper(android.database.Cursor);
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public void deactivate();
+    method public deprecated void deactivate();
     method public byte[] getBlob(int);
     method public int getColumnCount();
     method public int getColumnIndex(java.lang.String);
@@ -10225,8 +10263,9 @@
     method public boolean moveToPrevious();
     method public void registerContentObserver(android.database.ContentObserver);
     method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public boolean requery();
+    method public deprecated boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
@@ -11667,6 +11706,7 @@
     method public int getTextWidths(java.lang.String, float[]);
     method public android.graphics.Typeface getTypeface();
     method public android.graphics.Xfermode getXfermode();
+    method public boolean hasGlyph(java.lang.String);
     method public final boolean isAntiAlias();
     method public final boolean isDither();
     method public boolean isElegantTextHeight();
@@ -13308,6 +13348,10 @@
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_INFO_FOCUS_DISTANCE_CALIBRATION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_HYPERFOCAL_DISTANCE;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INTRINSIC_CALIBRATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_ROTATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_POSE_TRANSLATION;
+    field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES;
     field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_INPUT_STREAMS;
@@ -13727,7 +13771,11 @@
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCAL_LENGTH;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCUS_DISTANCE;
     field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Float, java.lang.Float>> LENS_FOCUS_RANGE;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_INTRINSIC_CALIBRATION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_ROTATION;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_POSE_TRANSLATION;
+    field public static final android.hardware.camera2.CaptureResult.Key<float[]> LENS_RADIAL_DISTORTION;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE;
     field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> REPROCESS_EFFECTIVE_EXPOSURE_FACTOR;
@@ -13859,6 +13907,8 @@
     method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRangesFor(android.util.Size);
     method public android.util.Size[] getHighSpeedVideoSizes();
     method public android.util.Size[] getHighSpeedVideoSizesFor(android.util.Range<java.lang.Integer>);
+    method public final int[] getInputFormats();
+    method public android.util.Size[] getInputSizes(int);
     method public final int[] getOutputFormats();
     method public long getOutputMinFrameDuration(int, android.util.Size);
     method public long getOutputMinFrameDuration(java.lang.Class<T>, android.util.Size);
@@ -13866,6 +13916,7 @@
     method public android.util.Size[] getOutputSizes(int);
     method public long getOutputStallDuration(int, android.util.Size);
     method public long getOutputStallDuration(java.lang.Class<T>, android.util.Size);
+    method public final int[] getValidOutputFormatsForInput(int);
     method public boolean isOutputSupportedFor(int);
     method public static boolean isOutputSupportedFor(java.lang.Class<T>);
     method public boolean isOutputSupportedFor(android.view.Surface);
@@ -15639,6 +15690,8 @@
     field public static final int CHANNEL_OUT_SURROUND = 1052; // 0x41c
     field public static final int ENCODING_AC3 = 5; // 0x5
     field public static final int ENCODING_DEFAULT = 1; // 0x1
+    field public static final int ENCODING_DTS = 7; // 0x7
+    field public static final int ENCODING_DTS_HD = 8; // 0x8
     field public static final int ENCODING_E_AC3 = 6; // 0x6
     field public static final int ENCODING_INVALID = 0; // 0x0
     field public static final int ENCODING_PCM_16BIT = 2; // 0x2
@@ -15926,6 +15979,16 @@
     field public static final int WRITE_NON_BLOCKING = 1; // 0x1
   }
 
+  public static class AudioTrack.Builder {
+    ctor public AudioTrack.Builder();
+    method public android.media.AudioTrack build() throws java.lang.UnsupportedOperationException;
+    method public android.media.AudioTrack.Builder setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setAudioFormat(android.media.AudioFormat) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setBufferSizeInBytes(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setSessionId(int) throws java.lang.IllegalArgumentException;
+    method public android.media.AudioTrack.Builder setTransferMode(int) throws java.lang.IllegalArgumentException;
+  }
+
   public static abstract interface AudioTrack.OnPlaybackPositionUpdateListener {
     method public abstract void onMarkerReached(android.media.AudioTrack);
     method public abstract void onPeriodicNotification(android.media.AudioTrack);
@@ -16089,6 +16152,7 @@
   public class ImageWriter implements java.lang.AutoCloseable {
     method public void close();
     method public android.media.Image dequeueInputImage();
+    method public int getFormat();
     method public int getMaxImages();
     method public static android.media.ImageWriter newInstance(android.view.Surface, int);
     method public void queueInputImage(android.media.Image);
@@ -16183,6 +16247,7 @@
     field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
     field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
     field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "video-bitrate";
+    field public static final int REASON_RECLAIMED = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
@@ -16198,6 +16263,7 @@
 
   public static abstract class MediaCodec.Callback {
     ctor public MediaCodec.Callback();
+    method public void onCodecReleased(android.media.MediaCodec, int);
     method public abstract void onError(android.media.MediaCodec, android.media.MediaCodec.CodecException);
     method public abstract void onInputBufferAvailable(android.media.MediaCodec, int);
     method public abstract void onOutputBufferAvailable(android.media.MediaCodec, int, android.media.MediaCodec.BufferInfo);
@@ -16463,6 +16529,7 @@
     method public static final boolean isCryptoSchemeSupported(java.util.UUID);
     method public final void release();
     method public final boolean requiresSecureDecoderComponent(java.lang.String);
+    method public final void setMediaDrmSession(byte[]) throws android.media.MediaCryptoException;
   }
 
   public final class MediaCryptoException extends java.lang.Exception {
@@ -16518,6 +16585,8 @@
     method public void removeKeys(byte[]);
     method public void restoreKeys(byte[], byte[]);
     method public void setOnEventListener(android.media.MediaDrm.OnEventListener);
+    method public void setOnExpirationUpdateListener(android.media.MediaDrm.OnExpirationUpdateListener, android.os.Handler);
+    method public void setOnKeysChangeListener(android.media.MediaDrm.OnKeysChangeListener, android.os.Handler);
     method public void setPropertyByteArray(java.lang.String, byte[]);
     method public void setPropertyString(java.lang.String, java.lang.String);
     method public void unprovisionDevice();
@@ -16526,6 +16595,11 @@
     field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
     field public static final int EVENT_SESSION_RECLAIMED = 5; // 0x5
     field public static final int EVENT_VENDOR_DEFINED = 4; // 0x4
+    field public static final int KEY_STATUS_EXPIRED = 1; // 0x1
+    field public static final int KEY_STATUS_INTERNAL_ERROR = 4; // 0x4
+    field public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2; // 0x2
+    field public static final int KEY_STATUS_PENDING = 3; // 0x3
+    field public static final int KEY_STATUS_USABLE = 0; // 0x0
     field public static final int KEY_TYPE_OFFLINE = 2; // 0x2
     field public static final int KEY_TYPE_RELEASE = 3; // 0x3
     field public static final int KEY_TYPE_STREAMING = 1; // 0x1
@@ -16552,6 +16626,11 @@
     method public int getRequestType();
   }
 
+  public static final class MediaDrm.KeyStatus {
+    method public byte[] getKeyId();
+    method public int getStatusCode();
+  }
+
   public static final class MediaDrm.MediaDrmStateException extends java.lang.IllegalStateException {
     method public java.lang.String getDiagnosticInfo();
   }
@@ -16560,6 +16639,14 @@
     method public abstract void onEvent(android.media.MediaDrm, byte[], int, int, byte[]);
   }
 
+  public static abstract interface MediaDrm.OnExpirationUpdateListener {
+    method public abstract void onExpirationUpdate(android.media.MediaDrm, byte[], long);
+  }
+
+  public static abstract interface MediaDrm.OnKeysChangeListener {
+    method public abstract void onKeysChange(android.media.MediaDrm, byte[], java.util.List<android.media.MediaDrm.KeyStatus>, boolean);
+  }
+
   public static final class MediaDrm.ProvisionRequest {
     method public byte[] getData();
     method public java.lang.String getDefaultUrl();
@@ -16646,6 +16733,7 @@
     field public static final java.lang.String KEY_MAX_INPUT_SIZE = "max-input-size";
     field public static final java.lang.String KEY_MAX_WIDTH = "max-width";
     field public static final java.lang.String KEY_MIME = "mime";
+    field public static final java.lang.String KEY_OPERATING_RATE = "operating-rate";
     field public static final java.lang.String KEY_PRIORITY = "priority";
     field public static final java.lang.String KEY_PROFILE = "profile";
     field public static final java.lang.String KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
@@ -16768,6 +16856,7 @@
     field public static final int METADATA_KEY_ARTIST = 2; // 0x2
     field public static final int METADATA_KEY_AUTHOR = 3; // 0x3
     field public static final int METADATA_KEY_BITRATE = 20; // 0x14
+    field public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25; // 0x19
     field public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; // 0x0
     field public static final int METADATA_KEY_COMPILATION = 15; // 0xf
     field public static final int METADATA_KEY_COMPOSER = 4; // 0x4
@@ -17168,6 +17257,24 @@
     method public abstract void onScanCompleted(java.lang.String, android.net.Uri);
   }
 
+  public final class MediaSync {
+    ctor public MediaSync();
+    method public void configureAudioTrack(android.media.AudioTrack, int);
+    method public void configureSurface(android.view.Surface);
+    method public final android.view.Surface createInputSurface();
+    method public boolean getTimestamp(android.media.MediaTimestamp);
+    method public void queueAudio(java.nio.ByteBuffer, int, int, long);
+    method public final void release();
+    method public void setCallback(android.media.MediaSync.Callback, android.os.Handler);
+    method public void setPlaybackRate(float, int);
+    field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
+  }
+
+  public static abstract class MediaSync.Callback {
+    ctor public MediaSync.Callback();
+    method public abstract void onReturnAudioBuffer(android.media.MediaSync, java.nio.ByteBuffer, int);
+  }
+
   public class MediaSyncEvent {
     method public static android.media.MediaSyncEvent createEvent(int) throws java.lang.IllegalArgumentException;
     method public int getAudioSessionId();
@@ -17177,6 +17284,13 @@
     field public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1; // 0x1
   }
 
+  public final class MediaTimestamp {
+    ctor public MediaTimestamp();
+    field public float clockRate;
+    field public long mediaTimeUs;
+    field public long nanoTime;
+  }
+
   public final class NotProvisionedException extends android.media.MediaDrmException {
     ctor public NotProvisionedException(java.lang.String);
   }
@@ -17986,13 +18100,24 @@
 
 package android.media.midi {
 
+  public final class MidiDevice implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+    method public android.media.midi.MidiDevice.MidiConnection connectPorts(android.media.midi.MidiInputPort, int);
+    method public android.media.midi.MidiDeviceInfo getInfo();
+    method public android.media.midi.MidiInputPort openInputPort(int);
+    method public android.media.midi.MidiOutputPort openOutputPort(int);
+  }
+
+  public class MidiDevice.MidiConnection implements java.io.Closeable {
+    method public void close() throws java.io.IOException;
+  }
+
   public final class MidiDeviceInfo implements android.os.Parcelable {
     method public int describeContents();
     method public int getId();
     method public int getInputPortCount();
-    method public android.media.midi.MidiDeviceInfo.PortInfo getInputPortInfo(int);
     method public int getOutputPortCount();
-    method public android.media.midi.MidiDeviceInfo.PortInfo getOutputPortInfo(int);
+    method public android.media.midi.MidiDeviceInfo.PortInfo[] getPortList();
     method public android.os.Bundle getProperties();
     method public int getType();
     method public boolean isPrivate();
@@ -18042,6 +18167,31 @@
     method public void onReceive(byte[], int, int, long) throws java.io.IOException;
   }
 
+  public final class MidiManager {
+    method public android.media.midi.MidiDeviceInfo[] getDeviceList();
+    method public void openBluetoothDevice(android.bluetooth.BluetoothDevice, android.media.midi.MidiManager.BluetoothOpenCallback, android.os.Handler);
+    method public void openDevice(android.media.midi.MidiDeviceInfo, android.media.midi.MidiManager.DeviceOpenCallback, android.os.Handler);
+    method public void registerDeviceCallback(android.media.midi.MidiManager.DeviceCallback, android.os.Handler);
+    method public void unregisterDeviceCallback(android.media.midi.MidiManager.DeviceCallback);
+  }
+
+  public static abstract class MidiManager.BluetoothOpenCallback {
+    ctor public MidiManager.BluetoothOpenCallback();
+    method public abstract void onDeviceOpened(android.bluetooth.BluetoothDevice, android.media.midi.MidiDevice);
+  }
+
+  public static class MidiManager.DeviceCallback {
+    ctor public MidiManager.DeviceCallback();
+    method public void onDeviceAdded(android.media.midi.MidiDeviceInfo);
+    method public void onDeviceRemoved(android.media.midi.MidiDeviceInfo);
+    method public void onDeviceStatusChanged(android.media.midi.MidiDeviceStatus);
+  }
+
+  public static abstract class MidiManager.DeviceOpenCallback {
+    ctor public MidiManager.DeviceOpenCallback();
+    method public abstract void onDeviceOpened(android.media.midi.MidiDeviceInfo, android.media.midi.MidiDevice);
+  }
+
   public final class MidiOutputPort extends android.media.midi.MidiSender implements java.io.Closeable {
     method public void close() throws java.io.IOException;
     method public void connect(android.media.midi.MidiReceiver);
@@ -18051,6 +18201,7 @@
 
   public abstract class MidiReceiver {
     ctor public MidiReceiver();
+    method public void flush() throws java.io.IOException;
     method public int getMaxMessageSize();
     method public abstract void onReceive(byte[], int, int, long) throws java.io.IOException;
     method public void send(byte[], int, int) throws java.io.IOException;
@@ -18820,6 +18971,12 @@
     field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
     field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
     field public static final java.lang.String META_DATA_CONTENT_RATING_SYSTEMS = "android.media.tv.metadata.CONTENT_RATING_SYSTEMS";
+    field public static final long TIME_SHIFT_INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L
+    field public static final int TIME_SHIFT_STATUS_AVAILABLE = 3; // 0x3
+    field public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2; // 0x2
+    field public static final int TIME_SHIFT_STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1; // 0x1
+    field public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = 4; // 0x4
     field public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3; // 0x3
     field public static final int VIDEO_UNAVAILABLE_REASON_TUNING = 1; // 0x1
     field public static final int VIDEO_UNAVAILABLE_REASON_UNKNOWN = 0; // 0x0
@@ -18862,6 +19019,9 @@
     method public void onSessionCreated(android.media.tv.TvInputManager.Session);
     method public void onSessionEvent(android.media.tv.TvInputManager.Session, java.lang.String, android.os.Bundle);
     method public void onSessionReleased(android.media.tv.TvInputManager.Session);
+    method public void onTimeShiftCurrentPositionChanged(android.media.tv.TvInputManager.Session, long);
+    method public void onTimeShiftStartPositionChanged(android.media.tv.TvInputManager.Session, long);
+    method public void onTimeShiftStatusChanged(android.media.tv.TvInputManager.Session, int);
     method public void onTrackSelected(android.media.tv.TvInputManager.Session, int, java.lang.String);
     method public void onTracksChanged(android.media.tv.TvInputManager.Session, java.util.List<android.media.tv.TvTrackInfo>);
     method public void onVideoAvailable(android.media.tv.TvInputManager.Session);
@@ -18904,6 +19064,7 @@
     method public void notifyContentAllowed();
     method public void notifyContentBlocked(android.media.tv.TvContentRating);
     method public void notifySessionEvent(java.lang.String, android.os.Bundle);
+    method public void notifyTimeShiftStatusChanged(int);
     method public void notifyTrackSelected(int, java.lang.String);
     method public void notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>);
     method public void notifyVideoAvailable();
@@ -18923,6 +19084,12 @@
     method public abstract void onSetStreamVolume(float);
     method public abstract boolean onSetSurface(android.view.Surface);
     method public void onSurfaceChanged(int, int, int);
+    method public long onTimeShiftGetCurrentPosition();
+    method public long onTimeShiftGetStartPosition();
+    method public void onTimeShiftPause();
+    method public void onTimeShiftResume();
+    method public void onTimeShiftSeekTo(long);
+    method public void onTimeShiftSetPlaybackRate(float, int);
     method public boolean onTouchEvent(android.view.MotionEvent);
     method public boolean onTrackballEvent(android.view.MotionEvent);
     method public abstract boolean onTune(android.net.Uri);
@@ -19004,8 +19171,13 @@
     method public void setMain();
     method public void setOnUnhandledInputEventListener(android.media.tv.TvView.OnUnhandledInputEventListener);
     method public void setStreamVolume(float);
+    method public void setTimeShiftPositionCallback(android.media.tv.TvView.TimeShiftPositionCallback);
     method public void setZOrderMediaOverlay(boolean);
     method public void setZOrderOnTop(boolean);
+    method public void timeShiftPause();
+    method public void timeShiftResume();
+    method public void timeShiftSeekTo(long);
+    method public void timeShiftSetPlaybackRate(float, int);
     method public void tune(java.lang.String, android.net.Uri);
     method public void tune(java.lang.String, android.net.Uri, android.os.Bundle);
   }
@@ -19014,6 +19186,12 @@
     method public abstract boolean onUnhandledInputEvent(android.view.InputEvent);
   }
 
+  public static abstract class TvView.TimeShiftPositionCallback {
+    ctor public TvView.TimeShiftPositionCallback();
+    method public void onTimeShiftCurrentPositionChanged(java.lang.String, long);
+    method public void onTimeShiftStartPositionChanged(java.lang.String, long);
+  }
+
   public static abstract class TvView.TvInputCallback {
     ctor public TvView.TvInputCallback();
     method public void onChannelRetuned(java.lang.String, android.net.Uri);
@@ -19022,6 +19200,7 @@
     method public void onContentBlocked(java.lang.String, android.media.tv.TvContentRating);
     method public void onDisconnected(java.lang.String);
     method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
+    method public void onTimeShiftStatusChanged(java.lang.String, int);
     method public void onTrackSelected(java.lang.String, int, java.lang.String);
     method public void onTracksChanged(java.lang.String, java.util.List<android.media.tv.TvTrackInfo>);
     method public void onVideoAvailable(java.lang.String);
@@ -20494,6 +20673,7 @@
 
   public static final class WifiEnterpriseConfig.Eap {
     field public static final int AKA = 5; // 0x5
+    field public static final int AKA_PRIME = 6; // 0x6
     field public static final int NONE = -1; // 0xffffffff
     field public static final int PEAP = 0; // 0x0
     field public static final int PWD = 3; // 0x3
@@ -24023,6 +24203,9 @@
   public class BatteryManager {
     method public int getIntProperty(int);
     method public long getLongProperty(int);
+    method public boolean isCharging();
+    field public static final java.lang.String ACTION_CHARGING = "android.os.action.CHARGING";
+    field public static final java.lang.String ACTION_DISCHARGING = "android.os.action.DISCHARGING";
     field public static final int BATTERY_HEALTH_COLD = 7; // 0x7
     field public static final int BATTERY_HEALTH_DEAD = 4; // 0x4
     field public static final int BATTERY_HEALTH_GOOD = 2; // 0x2
@@ -25072,6 +25255,7 @@
     method public android.os.Bundle getApplicationRestrictions(java.lang.String);
     method public long getSerialNumberForUser(android.os.UserHandle);
     method public int getUserCount();
+    method public long getUserCreationTime(int);
     method public android.os.UserHandle getUserForSerialNumber(long);
     method public java.lang.String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
@@ -25928,8 +26112,16 @@
     field public static final java.lang.String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
     field public static final java.lang.String ACTION_SET_TIMER = "android.intent.action.SET_TIMER";
     field public static final java.lang.String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
+    field public static final java.lang.String ACTION_VOICE_CANCEL_ALARM = "android.intent.action.VOICE_CANCEL_ALARM";
+    field public static final java.lang.String ACTION_VOICE_DELETE_ALARM = "android.intent.action.VOICE_DELETE_ALARM";
+    field public static final java.lang.String ALARM_SEARCH_MODE_ALL = "all";
+    field public static final java.lang.String ALARM_SEARCH_MODE_NEXT = "next";
+    field public static final java.lang.String ALARM_SEARCH_MODE_NONE = "none";
+    field public static final java.lang.String ALARM_SEARCH_MODE_TIME = "time";
+    field public static final java.lang.String EXTRA_ALARM_SEARCH_MODE = "android.intent.extra.alarm.ALARM_SEARCH_MODE";
     field public static final java.lang.String EXTRA_DAYS = "android.intent.extra.alarm.DAYS";
     field public static final java.lang.String EXTRA_HOUR = "android.intent.extra.alarm.HOUR";
+    field public static final java.lang.String EXTRA_IS_PM = "android.intent.extra.alarm.IS_PM";
     field public static final java.lang.String EXTRA_LENGTH = "android.intent.extra.alarm.LENGTH";
     field public static final java.lang.String EXTRA_MESSAGE = "android.intent.extra.alarm.MESSAGE";
     field public static final java.lang.String EXTRA_MINUTES = "android.intent.extra.alarm.MINUTES";
@@ -27608,6 +27800,8 @@
     method public static java.lang.String getVersion(android.content.Context);
     field public static final java.lang.String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final java.lang.String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
+    field public static final java.lang.String ACTION_STILL_IMAGE_CAMERA_COOLDOWN = "android.media.action.STILL_IMAGE_CAMERA_COOLDOWN";
+    field public static final java.lang.String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM";
     field public static final java.lang.String ACTION_VIDEO_CAPTURE = "android.media.action.VIDEO_CAPTURE";
     field public static final java.lang.String AUTHORITY = "media";
     field public static final java.lang.String EXTRA_DURATION_LIMIT = "android.intent.extra.durationLimit";
@@ -28081,6 +28275,8 @@
     field public static final java.lang.String ACTION_USAGE_ACCESS_SETTINGS = "android.settings.USAGE_ACCESS_SETTINGS";
     field public static final java.lang.String ACTION_USER_DICTIONARY_SETTINGS = "android.settings.USER_DICTIONARY_SETTINGS";
     field public static final java.lang.String ACTION_VOICE_CONTROL_AIRPLANE_MODE = "android.settings.VOICE_CONTROL_AIRPLANE_MODE";
+    field public static final java.lang.String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE = "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
+    field public static final java.lang.String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE = "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
     field public static final java.lang.String ACTION_VOICE_INPUT_SETTINGS = "android.settings.VOICE_INPUT_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
     field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
@@ -28089,6 +28285,9 @@
     field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
     field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
     field public static final java.lang.String EXTRA_AUTHORITIES = "authorities";
+    field public static final java.lang.String EXTRA_BATTERY_SAVER_MODE_ENABLED = "android.settings.extra.battery_saver_mode_enabled";
+    field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
+    field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
     field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
   }
 
@@ -29483,6 +29682,41 @@
     method public android.renderscript.ScriptGroup create();
   }
 
+  public class ScriptGroup2 extends android.renderscript.BaseObj {
+    ctor public ScriptGroup2(long, android.renderscript.RenderScript);
+    method public java.lang.Object[] execute(java.lang.Object...);
+  }
+
+  public static final class ScriptGroup2.Binding {
+    ctor public ScriptGroup2.Binding(android.renderscript.Script.FieldID, java.lang.Object);
+    method public android.renderscript.Script.FieldID getField();
+    method public java.lang.Object getValue();
+  }
+
+  public static final class ScriptGroup2.Builder {
+    ctor public ScriptGroup2.Builder(android.renderscript.RenderScript);
+    method public android.renderscript.ScriptGroup2.UnboundValue addInput();
+    method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    method public android.renderscript.ScriptGroup2.Closure addInvoke(android.renderscript.Script.InvokeID, java.lang.Object...);
+    method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    method public android.renderscript.ScriptGroup2.Closure addKernel(android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object...);
+    method public android.renderscript.ScriptGroup2 create(java.lang.String, android.renderscript.ScriptGroup2.Future...);
+  }
+
+  public static class ScriptGroup2.Closure extends android.renderscript.BaseObj {
+    ctor public ScriptGroup2.Closure(long, android.renderscript.RenderScript);
+    ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.KernelID, android.renderscript.Type, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    ctor public ScriptGroup2.Closure(android.renderscript.RenderScript, android.renderscript.Script.InvokeID, java.lang.Object[], java.util.Map<android.renderscript.Script.FieldID, java.lang.Object>);
+    method public android.renderscript.ScriptGroup2.Future getGlobal(android.renderscript.Script.FieldID);
+    method public android.renderscript.ScriptGroup2.Future getReturn();
+  }
+
+  public static class ScriptGroup2.Future {
+  }
+
+  public static class ScriptGroup2.UnboundValue {
+  }
+
   public abstract class ScriptIntrinsic extends android.renderscript.Script {
   }
 
@@ -30031,6 +30265,7 @@
     method public final void setOnNotificationPostedTrim(int);
     method public void unregisterAsSystemService() throws android.os.RemoteException;
     field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1
+    field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
     field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
     field public static final int INTERRUPTION_FILTER_NONE = 3; // 0x3
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
@@ -30087,6 +30322,7 @@
     method public abstract byte[] read() throws android.os.RemoteException;
     method public abstract void setOemUnlockEnabled(boolean) throws android.os.RemoteException;
     method public abstract void wipe() throws android.os.RemoteException;
+    method public abstract void wipeIfAllowed(android.os.Bundle, android.app.PendingIntent) throws android.os.RemoteException;
     method public abstract int write(byte[]) throws android.os.RemoteException;
   }
 
@@ -30098,7 +30334,14 @@
     method public byte[] read();
     method public void setOemUnlockEnabled(boolean);
     method public void wipe();
+    method public void wipeIfAllowed(android.os.Bundle, android.app.PendingIntent);
     method public int write(byte[]);
+    field public static final java.lang.String ACTION_WIPE_IF_ALLOWED = "android.service.persistentdata.action.WIPE_IF_ALLOWED";
+    field public static final java.lang.String EXTRA_WIPE_IF_ALLOWED_CALLBACK = "android.service.persistentdata.extra.WIPE_IF_ALLOWED_CALLBACK";
+    field public static final int STATUS_ERROR_NETWORK_ERROR = 2; // 0x2
+    field public static final int STATUS_ERROR_NOT_COMPLIANT = 3; // 0x3
+    field public static final int STATUS_ERROR_REMOTE_EXCEPTION = 1; // 0x1
+    field public static final int STATUS_SUCCESS = 0; // 0x0
   }
 
 }
@@ -30198,6 +30441,7 @@
     method public void showSession(android.os.Bundle, int);
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService";
     field public static final java.lang.String SERVICE_META_DATA = "android.voice_interaction";
+    field public static final int START_SOURCE_ASSIST_GESTURE = 4; // 0x4
     field public static final int START_WITH_ASSIST = 1; // 0x1
     field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
@@ -30206,6 +30450,7 @@
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
     method public void finish();
+    method public android.content.Context getContext();
     method public android.view.LayoutInflater getLayoutInflater();
     method public android.app.Dialog getWindow();
     method public void hide();
@@ -32425,6 +32670,11 @@
     field public static final int PHONE_TYPE_GSM = 1; // 0x1
     field public static final int PHONE_TYPE_NONE = 0; // 0x0
     field public static final int PHONE_TYPE_SIP = 3; // 0x3
+    field public static final int SIM_ACTIVATION_RESULT_CANCELED = 4; // 0x4
+    field public static final int SIM_ACTIVATION_RESULT_COMPLETE = 0; // 0x0
+    field public static final int SIM_ACTIVATION_RESULT_FAILED = 3; // 0x3
+    field public static final int SIM_ACTIVATION_RESULT_IN_PROGRESS = 2; // 0x2
+    field public static final int SIM_ACTIVATION_RESULT_NOT_SUPPORTED = 1; // 0x1
     field public static final int SIM_STATE_ABSENT = 1; // 0x1
     field public static final int SIM_STATE_NETWORK_LOCKED = 4; // 0x4
     field public static final int SIM_STATE_PIN_REQUIRED = 2; // 0x2
@@ -32974,7 +33224,7 @@
     ctor public MockCursor();
     method public void close();
     method public void copyStringToBuffer(int, android.database.CharArrayBuffer);
-    method public void deactivate();
+    method public deprecated void deactivate();
     method public byte[] getBlob(int);
     method public int getColumnCount();
     method public int getColumnIndex(java.lang.String);
@@ -33007,8 +33257,9 @@
     method public boolean moveToPrevious();
     method public void registerContentObserver(android.database.ContentObserver);
     method public void registerDataSetObserver(android.database.DataSetObserver);
-    method public boolean requery();
+    method public deprecated boolean requery();
     method public android.os.Bundle respond(android.os.Bundle);
+    method public void setExtras(android.os.Bundle);
     method public void setNotificationUri(android.content.ContentResolver, android.net.Uri);
     method public void unregisterContentObserver(android.database.ContentObserver);
     method public void unregisterDataSetObserver(android.database.DataSetObserver);
@@ -33040,6 +33291,7 @@
     method public android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String);
     method public java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
     method public android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
     method public android.graphics.drawable.Drawable getApplicationBanner(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -33052,12 +33304,12 @@
     method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int getComponentEnabledSetting(android.content.ComponentName);
     method public android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method public java.lang.String getDefaultBrowserPackageName(int);
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(java.lang.String);
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
@@ -33102,6 +33354,7 @@
     method public void revokePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public void setApplicationEnabledSetting(java.lang.String, int, int);
     method public void setComponentEnabledSetting(android.content.ComponentName, int, int);
+    method public boolean setDefaultBrowserPackageName(java.lang.String, int);
     method public void setInstallerPackageName(java.lang.String, java.lang.String);
     method public void verifyPendingInstall(int, int);
   }
@@ -33424,6 +33677,9 @@
     method public final void increaseWidthTo(int);
     method public boolean isRtlCharAt(int);
     method protected final boolean isSpanned();
+    field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
+    field public static final int BREAK_STRATEGY_HIGH_QUALITY = 1; // 0x1
+    field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
     field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
     field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
   }
@@ -34955,6 +35211,7 @@
     ctor public TransitionManager();
     method public static void beginDelayedTransition(android.view.ViewGroup);
     method public static void beginDelayedTransition(android.view.ViewGroup, android.transition.Transition);
+    method public static void endTransitions(android.view.ViewGroup);
     method public static void go(android.transition.Scene);
     method public static void go(android.transition.Scene, android.transition.Transition);
     method public void setTransition(android.transition.Scene, android.transition.Transition);
@@ -35973,10 +36230,10 @@
     method public java.lang.String getName();
     method public int getProductId();
     method public int getSources();
-    method public java.lang.String getUniqueId();
     method public int getVendorId();
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
+    method public boolean hasMic();
     method public boolean isVirtual();
     method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -37062,6 +37319,7 @@
     method public boolean dispatchNestedPreScroll(int, int, int[], int[]);
     method public boolean dispatchNestedScroll(int, int, int, int, int[]);
     method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void dispatchProvideAssistStructure(android.view.ViewAssistStructure);
     method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>);
     method protected void dispatchSetActivated(boolean);
@@ -37318,7 +37576,8 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
-    method public void onProvideAssistStructure(android.view.ViewAssistStructure, android.os.Bundle);
+    method public void onProvideAssistStructure(android.view.ViewAssistStructure);
+    method public void onProvideVirtualAssistStructure(android.view.ViewAssistStructure);
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method public void onRtlPropertiesChanged(int);
     method protected android.os.Parcelable onSaveInstanceState();
@@ -37728,14 +37987,36 @@
 
   public abstract class ViewAssistStructure {
     ctor public ViewAssistStructure();
+    method public abstract void asyncCommit();
+    method public abstract android.view.ViewAssistStructure asyncNewChild(int);
+    method public abstract void clearExtras();
+    method public abstract android.os.Bundle editExtras();
+    method public abstract int getChildCount();
     method public abstract java.lang.CharSequence getHint();
     method public abstract java.lang.CharSequence getText();
     method public abstract int getTextSelectionEnd();
     method public abstract int getTextSelectionStart();
+    method public abstract android.view.ViewAssistStructure newChild(int);
+    method public abstract void setAccessibilityFocused(boolean);
+    method public abstract void setActivated(boolean);
+    method public abstract void setCheckable(boolean);
+    method public abstract void setChecked(boolean);
+    method public abstract void setChildCount(int);
+    method public abstract void setClassName(java.lang.String);
+    method public abstract void setClickable(boolean);
+    method public abstract void setContentDescription(java.lang.CharSequence);
+    method public abstract void setDimens(int, int, int, int, int, int);
+    method public abstract void setEnabled(boolean);
+    method public abstract void setFocusable(boolean);
+    method public abstract void setFocused(boolean);
     method public abstract void setHint(java.lang.CharSequence);
+    method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String);
+    method public abstract void setLongClickable(boolean);
+    method public abstract void setSelected(boolean);
     method public abstract void setText(java.lang.CharSequence);
     method public abstract void setText(java.lang.CharSequence, int, int);
     method public abstract void setTextPaint(android.text.TextPaint);
+    method public abstract void setVisibility(int);
   }
 
   public class ViewConfiguration {
@@ -38768,9 +39049,11 @@
     method public void setVisibleToUser(boolean);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int ACTION_ACCESSIBILITY_FOCUS = 64; // 0x40
+    field public static final java.lang.String ACTION_ARGUMENT_COLUMN_INT = "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
     field public static final java.lang.String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN = "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
     field public static final java.lang.String ACTION_ARGUMENT_HTML_ELEMENT_STRING = "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
     field public static final java.lang.String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
+    field public static final java.lang.String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SELECTION_START_INT = "ACTION_ARGUMENT_SELECTION_START_INT";
     field public static final java.lang.String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE = "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
@@ -38828,6 +39111,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_BACKWARD;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_FORWARD;
+    field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_TO_POSITION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
@@ -40680,6 +40964,7 @@
     method public abstract boolean onKeyUp(int, android.view.KeyEvent);
     method public abstract void onMeasure(int, int);
     method public abstract void onOverScrolled(int, int, boolean, boolean);
+    method public abstract void onProvideVirtualAssistStructure(android.view.ViewAssistStructure);
     method public abstract void onScrollChanged(int, int, int, int);
     method public abstract void onSizeChanged(int, int, int, int);
     method public abstract void onStartTemporaryDetach();
@@ -42887,6 +43172,7 @@
     method public void endBatchEdit();
     method public boolean extractText(android.view.inputmethod.ExtractedTextRequest, android.view.inputmethod.ExtractedText);
     method public final int getAutoLinkMask();
+    method public int getBreakStrategy();
     method public int getCompoundDrawablePadding();
     method public android.content.res.ColorStateList getCompoundDrawableTintList();
     method public android.graphics.PorterDuff.Mode getCompoundDrawableTintMode();
@@ -42988,6 +43274,7 @@
     method public void removeTextChangedListener(android.text.TextWatcher);
     method public void setAllCaps(boolean);
     method public final void setAutoLinkMask(int);
+    method public void setBreakStrategy(int);
     method public void setCompoundDrawablePadding(int);
     method public void setCompoundDrawableTintList(android.content.res.ColorStateList);
     method public void setCompoundDrawableTintMode(android.graphics.PorterDuff.Mode);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index c2b9d3e..0c433c3 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -6,6 +6,16 @@
 
 }
 
+package android.database {
+
+  public abstract class AbstractCursor implements android.database.CrossProcessCursor {
+    field protected java.lang.Long mCurrentRowID;
+    field protected int mRowIdColumnIndex;
+    field protected java.util.HashMap<java.lang.Long, java.util.Map<java.lang.String, java.lang.Object>> mUpdatedRows;
+  }
+
+}
+
 package android.media {
 
   public class AudioFormat {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 0a53371..908d46e 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -1189,12 +1189,12 @@
     private void runSetWatchHeap() throws Exception {
         String proc = nextArgRequired();
         String limit = nextArgRequired();
-        mAm.setDumpHeapDebugLimit(proc, Long.parseLong(limit));
+        mAm.setDumpHeapDebugLimit(proc, 0, Long.parseLong(limit), null);
     }
 
     private void runClearWatchHeap() throws Exception {
         String proc = nextArgRequired();
-        mAm.setDumpHeapDebugLimit(proc, -1);
+        mAm.setDumpHeapDebugLimit(proc, 0, -1, null);
     }
 
     private void runBugReport() throws Exception {
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index c86fd53..c5af992 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -7,6 +7,12 @@
 
 #define LOG_TAG "appproc"
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <utils/Log.h>
@@ -17,11 +23,6 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <private/android_filesystem_config.h>  // for AID_SYSTEM
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/prctl.h>
-
 namespace android {
 
 static void app_usage()
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index 197e36b..84158d3 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -1,3 +1,6 @@
+#include <dirent.h>
+#include <sys/stat.h>
+
 #include "idmap.h"
 
 #include <UniquePtr.h>
@@ -9,8 +12,6 @@
 #include <utils/String16.h>
 #include <utils/String8.h>
 
-#include <dirent.h>
-
 #define NO_OVERLAY_TAG (-1000)
 
 using namespace android;
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 89dd079..b43c462 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -30,6 +30,7 @@
 import android.content.pm.IPackageDataObserver;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageManager;
+import android.content.pm.IPackageMoveObserver;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
@@ -55,12 +56,12 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import libcore.io.IoUtils;
+
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.SizedInputStream;
 
-import libcore.io.IoUtils;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
@@ -234,6 +235,10 @@
             return runForceDexOpt();
         }
 
+        if ("move".equals(op)) {
+            return runMove();
+        }
+
         try {
             if (args.length == 1) {
                 if (args[0].equalsIgnoreCase("-l")) {
@@ -1278,6 +1283,51 @@
         }
     }
 
+    class LocalPackageMoveObserver extends IPackageMoveObserver.Stub {
+        boolean finished;
+        int returnCode;
+
+        @Override
+        public void packageMoved(String packageName, int returnCode) throws RemoteException {
+            synchronized (this) {
+                this.finished = true;
+                this.returnCode = returnCode;
+                notifyAll();
+            }
+        }
+    }
+
+    public int runMove() {
+        final String packageName = nextArg();
+        String volumeUuid = nextArg();
+        if ("internal".equals(volumeUuid)) {
+            volumeUuid = null;
+        }
+
+        final LocalPackageMoveObserver obs = new LocalPackageMoveObserver();
+        try {
+            mPm.movePackageAndData(packageName, volumeUuid, obs);
+
+            synchronized (obs) {
+                while (!obs.finished) {
+                    try {
+                        obs.wait();
+                    } catch (InterruptedException e) {
+                    }
+                }
+                if (obs.returnCode == PackageManager.MOVE_SUCCEEDED) {
+                    System.out.println("Success");
+                    return 0;
+                } else {
+                    System.err.println("Failure [" + obs.returnCode + "]");
+                    return 1;
+                }
+            }
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
     private int runUninstall() throws RemoteException {
         int flags = 0;
         int userId = UserHandle.USER_ALL;
@@ -1335,7 +1385,8 @@
         }
 
         final LocalIntentReceiver receiver = new LocalIntentReceiver();
-        mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId);
+        mInstaller.uninstall(pkg, null /* callerPackageName */, flags,
+                receiver.getIntentSender(), userId);
 
         final Intent result = receiver.getResult();
         final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
@@ -1813,13 +1864,14 @@
         System.err.println("       pm list users");
         System.err.println("       pm path PACKAGE");
         System.err.println("       pm dump PACKAGE");
-        System.err.println("       pm install [-lrtsfd] [-i PACKAGE] [PATH]");
+        System.err.println("       pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]");
         System.err.println("       pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
         System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
         System.err.println("       pm install-commit SESSION_ID");
         System.err.println("       pm install-abandon SESSION_ID");
         System.err.println("       pm uninstall [-k] [--user USER_ID] PACKAGE");
         System.err.println("       pm set-installer PACKAGE INSTALLER");
+        System.err.println("       pm move PACKAGE [internal|UUID]");
         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");
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index da48709..02a329d 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -16,7 +16,12 @@
 
 package android.animation;
 
+import android.content.res.Configuration;
 import android.content.res.ConstantState;
+import android.content.res.Resources;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.animation.AnimationUtils;
 
 import java.util.ArrayList;
 
@@ -25,6 +30,29 @@
  * started, ended, and have <code>AnimatorListeners</code> added to them.
  */
 public abstract class Animator implements Cloneable {
+    /**
+     * Set this hint when duration for the animation does not need to be scaled. By default, no
+     * scaling is applied to the duration.
+     */
+    public static final int HINT_NO_SCALE = 0;
+
+    /**
+     * Set this scale hint (using {@link #setDurationScaleHint(int, Resources)} when the animation's
+     * moving distance is proportional to the screen size. (e.g. a view coming in from the bottom of
+     * the screen to top/center). With this scale hint set, the animation duration will be
+     * automatically scaled based on screen size.
+     */
+    public static final int HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE = 1;
+
+    /**
+     * Set this scale hint (using {@link #setDurationScaleHint(int, Resources)}) if the animation
+     * has pre-defined moving distance in dp that does not vary from device to device. This is
+     * extremely useful when the animation needs to run on both phones/tablets and TV, because TV
+     * has inflated dp and therefore will have a longer visual arc for the same animation than on
+     * the phone. This hint is used to calculate a scaling factor to compensate for different
+     * visual arcs while maintaining the same angular velocity for the animation.
+     */
+    public static final int HINT_DISTANCE_DEFINED_IN_DP = 2;
 
     /**
      * The set of listeners to be sent events through the life of an animation.
@@ -55,6 +83,24 @@
     private AnimatorConstantState mConstantState;
 
     /**
+     * Scaling factor for an animation that moves across the whole screen.
+     */
+    float mScreenSizeBasedDurationScale = 1.0f;
+
+    /**
+     * Scaling factor for an animation that is defined to move the same amount of dp across all
+     * devices.
+     */
+    float mDpBasedDurationScale = 1.0f;
+
+    /**
+     * By default, the scaling assumes the animation moves across the entire screen.
+     */
+    int mDurationScaleHint = HINT_NO_SCALE;
+
+    private final static boolean ANIM_DEBUG = false;
+
+    /**
      * Starts this animation. If the animation has a nonzero startDelay, the animation will start
      * running after that delay elapses. A non-delayed animation will have its initial
      * value(s) set immediately, followed by calls to
@@ -184,6 +230,78 @@
     public abstract long getDuration();
 
     /**
+     * Hints how duration scaling factor should be calculated. The duration will not be scaled when
+     * hint is set to {@link #HINT_NO_SCALE}. Otherwise, the duration will be automatically scaled
+     * per device to achieve the same look and feel across different devices. In order to do
+     * that, the same angular velocity of the animation will be needed on different devices in
+     * users' field of view. Therefore, the duration scale factor is determined by the ratio of the
+     * angular movement on current devices to that on the baseline device (i.e. Nexus 5).
+     *
+     * @param hint an indicator on how the animation is defined. The hint could be
+     *             {@link #HINT_NO_SCALE}, {@link #HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE} or
+     *             {@link #HINT_DISTANCE_DEFINED_IN_DP}.
+     * @param res The resources {@see android.content.res.Resources} for getting display metrics
+     */
+    public void setDurationScaleHint(int hint, Resources res) {
+        if (ANIM_DEBUG) {
+            Log.d("ANIM_DEBUG", "distance based duration hint: " + hint);
+        }
+        if (hint == mDurationScaleHint) {
+            return;
+        }
+        mDurationScaleHint = hint;
+        if (hint != HINT_NO_SCALE) {
+            int uiMode = res.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK;
+            DisplayMetrics metrics = res.getDisplayMetrics();
+            float width = metrics.widthPixels / metrics.xdpi;
+            float height = metrics.heightPixels / metrics.ydpi;
+            float viewingDistance = AnimationUtils.getViewingDistance(width, height, uiMode);
+            if (ANIM_DEBUG) {
+                Log.d("ANIM_DEBUG", "width, height, viewing distance, uimode: "
+                        + width + ", " + height + ", " + viewingDistance + ", " + uiMode);
+            }
+            mScreenSizeBasedDurationScale = AnimationUtils
+                    .getScreenSizeBasedDurationScale(width, height, viewingDistance);
+            mDpBasedDurationScale = AnimationUtils.getDpBasedDurationScale(
+                    metrics.density, metrics.xdpi, viewingDistance);
+            if (ANIM_DEBUG) {
+                Log.d("ANIM_DEBUG", "screen based scale, dp based scale: " +
+                        mScreenSizeBasedDurationScale + ", " + mDpBasedDurationScale);
+            }
+        }
+    }
+
+    // Copies duration scale hint and scaling factors to the new animation.
+    void copyDurationScaleInfoTo(Animator anim) {
+        anim.mDurationScaleHint = mDurationScaleHint;
+        anim.mScreenSizeBasedDurationScale = mScreenSizeBasedDurationScale;
+        anim.mDpBasedDurationScale = mDpBasedDurationScale;
+    }
+
+    /**
+     * @return The scaled duration calculated based on distance of movement (as defined by the
+     * animation) and perceived velocity (derived from the duration set on the animation for
+     * baseline device)
+     */
+    public long getDistanceBasedDuration() {
+        return (long) (getDuration() * getDistanceBasedDurationScale());
+    }
+
+    /**
+     * @return scaling factor of duration based on the duration scale hint. A scaling factor of 1
+     * means no scaling will be applied to the duration.
+     */
+    float getDistanceBasedDurationScale() {
+        if (mDurationScaleHint == HINT_DISTANCE_PROPORTIONAL_TO_SCREEN_SIZE) {
+            return mScreenSizeBasedDurationScale;
+        } else if (mDurationScaleHint == HINT_DISTANCE_DEFINED_IN_DP) {
+            return mDpBasedDurationScale;
+        } else {
+            return 1f;
+        }
+    }
+
+    /**
      * The time interpolator used in calculating the elapsed fraction of the
      * animation. The interpolator determines whether the animation runs with
      * linear or non-linear motion, such as acceleration and deceleration. The
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index 021194c..df5a4cb 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -68,6 +68,14 @@
     private static final int VALUE_TYPE_INT         = 1;
     private static final int VALUE_TYPE_PATH        = 2;
     private static final int VALUE_TYPE_COLOR       = 3;
+    private static final int VALUE_TYPE_UNDEFINED   = 4;
+
+    /**
+     * Enum values used in XML attributes to indicate the duration scale hint.
+     */
+    private static final int HINT_NO_SCALE                  = 0;
+    private static final int HINT_PROPORTIONAL_TO_SCREEN    = 1;
+    private static final int HINT_DEFINED_IN_DP             = 2;
 
     private static final boolean DBG_ANIMATOR_INFLATER = false;
 
@@ -299,8 +307,6 @@
     private static PropertyValuesHolder getPVH(TypedArray styledAttributes, int valueType,
             int valueFromId, int valueToId, String propertyName) {
 
-        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
-
         TypedValue tvFrom = styledAttributes.peekValue(valueFromId);
         boolean hasFrom = (tvFrom != null);
         int fromType = hasFrom ? tvFrom.type : 0;
@@ -308,6 +314,17 @@
         boolean hasTo = (tvTo != null);
         int toType = hasTo ? tvTo.type : 0;
 
+        if (valueType == VALUE_TYPE_UNDEFINED) {
+            // Check whether it's color type. If not, fall back to default type (i.e. float type)
+            if ((hasFrom && isColorType(fromType)) || (hasTo && isColorType(toType))) {
+                valueType = VALUE_TYPE_COLOR;
+            } else {
+                valueType = VALUE_TYPE_FLOAT;
+            }
+        }
+
+        boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
+
         PropertyValuesHolder returnValue = null;
 
         if (valueType == VALUE_TYPE_PATH) {
@@ -341,12 +358,8 @@
         } else {
             TypeEvaluator evaluator = null;
             // Integer and float value types are handled here.
-            if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                    (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
-                    (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                            (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
+            if (valueType == VALUE_TYPE_COLOR) {
                 // special case for colors: ignore valueType and get ints
-                getFloats = false;
                 evaluator = ArgbEvaluator.getInstance();
             }
             if (getFloats) {
@@ -383,8 +396,7 @@
                 if (hasFrom) {
                     if (fromType == TypedValue.TYPE_DIMENSION) {
                         valueFrom = (int) styledAttributes.getDimension(valueFromId, 0f);
-                    } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                            (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                    } else if (isColorType(fromType)) {
                         valueFrom = styledAttributes.getColor(valueFromId, 0);
                     } else {
                         valueFrom = styledAttributes.getInt(valueFromId, 0);
@@ -392,8 +404,7 @@
                     if (hasTo) {
                         if (toType == TypedValue.TYPE_DIMENSION) {
                             valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
-                        } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                                (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                        } else if (isColorType(toType)) {
                             valueTo = styledAttributes.getColor(valueToId, 0);
                         } else {
                             valueTo = styledAttributes.getInt(valueToId, 0);
@@ -406,8 +417,7 @@
                     if (hasTo) {
                         if (toType == TypedValue.TYPE_DIMENSION) {
                             valueTo = (int) styledAttributes.getDimension(valueToId, 0f);
-                        } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                                (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                        } else if (isColorType(toType)) {
                             valueTo = styledAttributes.getColor(valueToId, 0);
                         } else {
                             valueTo = styledAttributes.getInt(valueToId, 0);
@@ -613,8 +623,7 @@
             if (hasFrom) {
                 if (fromType == TypedValue.TYPE_DIMENSION) {
                     valueFrom = (int) arrayAnimator.getDimension(valueFromIndex, 0f);
-                } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                        (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                } else if (isColorType(fromType)) {
                     valueFrom = arrayAnimator.getColor(valueFromIndex, 0);
                 } else {
                     valueFrom = arrayAnimator.getInt(valueFromIndex, 0);
@@ -622,8 +631,7 @@
                 if (hasTo) {
                     if (toType == TypedValue.TYPE_DIMENSION) {
                         valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
-                    } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                            (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                    } else if (isColorType(toType)) {
                         valueTo = arrayAnimator.getColor(valueToIndex, 0);
                     } else {
                         valueTo = arrayAnimator.getInt(valueToIndex, 0);
@@ -636,8 +644,7 @@
                 if (hasTo) {
                     if (toType == TypedValue.TYPE_DIMENSION) {
                         valueTo = (int) arrayAnimator.getDimension(valueToIndex, 0f);
-                    } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
-                            (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+                    } else if (isColorType(toType)) {
                         valueTo = arrayAnimator.getColor(valueToIndex, 0);
                     } else {
                         valueTo = arrayAnimator.getInt(valueToIndex, 0);
@@ -691,6 +698,9 @@
                 int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER);
                 createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering,
                         pixelSize);
+                final int hint = a.getInt(R.styleable.Animator_durationScaleHint,
+                        HINT_NO_SCALE);
+                anim.setDurationScaleHint(hint, res);
                 a.recycle();
             } else if (name.equals("propertyValuesHolder")) {
                 PropertyValuesHolder[] values = loadValues(res, theme, parser,
@@ -749,7 +759,8 @@
                 }
                 String propertyName = a.getString(R.styleable.PropertyValuesHolder_propertyName);
                 int valueType = a.getInt(R.styleable.PropertyValuesHolder_valueType,
-                        VALUE_TYPE_FLOAT);
+                        VALUE_TYPE_UNDEFINED);
+
                 PropertyValuesHolder pvh = loadPvh(res, theme, parser, propertyName, valueType);
                 if (pvh == null) {
                     pvh = getPVH(a, valueType,
@@ -793,6 +804,7 @@
         }
     }
 
+    // Load property values holder if there are keyframes defined in it. Otherwise return null.
     private static PropertyValuesHolder loadPvh(Resources res, Theme theme, XmlPullParser parser,
             String propertyName, int valueType)
             throws XmlPullParserException, IOException {
@@ -928,7 +940,17 @@
 
         float fraction = a.getFloat(R.styleable.Keyframe_fraction, -1);
 
-        boolean hasValue = a.peekValue(R.styleable.Keyframe_value) != null;
+        TypedValue keyframeValue = a.peekValue(R.styleable.Keyframe_value);
+        boolean hasValue = (keyframeValue != null);
+        if (valueType == VALUE_TYPE_UNDEFINED) {
+            // When no value type is provided, check whether it's a color type first.
+            // If not, fall back to default value type (i.e. float type).
+            if (hasValue && isColorType(keyframeValue.type)) {
+                valueType = VALUE_TYPE_COLOR;
+            } else {
+                valueType = VALUE_TYPE_FLOAT;
+            }
+        }
 
         if (hasValue) {
             switch (valueType) {
@@ -947,6 +969,11 @@
                     Keyframe.ofInt(fraction);
         }
 
+        final int resID = a.getResourceId(R.styleable.Keyframe_interpolator, 0);
+        if (resID > 0) {
+            final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID);
+            keyframe.setInterpolator(interpolator);
+        }
         a.recycle();
 
         return keyframe;
@@ -1010,6 +1037,9 @@
             anim.setInterpolator(interpolator);
         }
 
+        final int hint = arrayAnimator.getInt(R.styleable.Animator_durationScaleHint,
+                HINT_NO_SCALE);
+        anim.setDurationScaleHint(hint, res);
         arrayAnimator.recycle();
         if (arrayObjectAnimator != null) {
             arrayObjectAnimator.recycle();
@@ -1023,4 +1053,8 @@
             return sTmpTypedValue.changingConfigurations;
         }
     }
+
+    private static boolean isColorType(int type) {
+       return (type >= TypedValue.TYPE_FIRST_COLOR_INT) && (type <= TypedValue.TYPE_LAST_COLOR_INT);
+    }
 }
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 53d5237..dd5f18e 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -519,6 +519,7 @@
 
         for (Node node : mNodes) {
             node.animation.setAllowRunningAsynchronously(false);
+            copyDurationScaleInfoTo(node.animation);
         }
 
         if (mDuration >= 0) {
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 3f71d51..f9333739 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -50,9 +50,11 @@
  * value. Alternatively, you can leave the fractions off and the keyframes will be equally
  * distributed within the total duration. Also, a keyframe with no value will derive its value
  * from the target object when the animator starts, just like animators with only one
- * value specified.</p>
+ * value specified. In addition, an optional interpolator can be specified. The interpolator will
+ * be applied on the interval between the keyframe that the interpolator is set on and the previous
+ * keyframe. When no interpolator is supplied, the default linear interpolator will be used. </p>
  *
- * {@sample development/samples/ApiDemos/res/anim/object_animator_pvh_kf.xml KeyframeResources}
+ * {@sample development/samples/ApiDemos/res/anim/object_animator_pvh_kf_interpolated.xml KeyframeResources}
  *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
diff --git a/core/java/android/animation/TimeAnimator.java b/core/java/android/animation/TimeAnimator.java
index 1738ade..1ba68df 100644
--- a/core/java/android/animation/TimeAnimator.java
+++ b/core/java/android/animation/TimeAnimator.java
@@ -51,6 +51,7 @@
     public void setCurrentPlayTime(long playTime) {
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         mStartTime = Math.max(mStartTime, currentTime - playTime);
+        mStartTimeCommitted = true; // do not allow start time to be compensated for jank
         animationFrame(currentTime);
     }
 
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 85dc832..275e78e 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -17,9 +17,13 @@
 package android.animation;
 
 import android.annotation.CallSuper;
+import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
+import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.Choreographer;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AnimationUtils;
@@ -64,6 +68,8 @@
  */
 @SuppressWarnings("unchecked")
 public class ValueAnimator extends Animator {
+    private static final String TAG = "ValueAnimator";
+    private static final boolean DEBUG = false;
 
     /**
      * Internal constants
@@ -85,12 +91,30 @@
      * to clone() to make deep copies of them.
      */
 
-    // The first time that the animation's animateFrame() method is called. This time is used to
-    // determine elapsed time (and therefore the elapsed fraction) in subsequent calls
-    // to animateFrame()
+    /**
+     * The first time that the animation's animateFrame() method is called. This time is used to
+     * determine elapsed time (and therefore the elapsed fraction) in subsequent calls
+     * to animateFrame().
+     *
+     * Whenever mStartTime is set, you must also update mStartTimeCommitted.
+     */
     long mStartTime;
 
     /**
+     * When true, the start time has been firmly committed as a chosen reference point in
+     * time by which the progress of the animation will be evaluated.  When false, the
+     * start time may be updated when the first animation frame is committed so as
+     * to compensate for jank that may have occurred between when the start time was
+     * initialized and when the frame was actually drawn.
+     *
+     * This flag is generally set to false during the first frame of the animation
+     * when the animation playing state transitions from STOPPED to RUNNING or
+     * resumes after having been paused.  This flag is set to true when the start time
+     * is firmly committed and should not be further compensated for jank.
+     */
+    boolean mStartTimeCommitted;
+
+    /**
      * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
      * to a value.
      */
@@ -528,6 +552,7 @@
      * value makes it easier to compose statements together that construct and then set the
      * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
      */
+    @Override
     public ValueAnimator setDuration(long duration) {
         if (duration < 0) {
             throw new IllegalArgumentException("Animators cannot have negative duration: " +
@@ -539,7 +564,7 @@
     }
 
     private void updateScaledDuration() {
-        mDuration = (long)(mUnscaledDuration * sDurationScale);
+        mDuration = (long)(mUnscaledDuration * sDurationScale * getDistanceBasedDurationScale());
     }
 
     /**
@@ -547,6 +572,7 @@
      *
      * @return The length of the animation, in milliseconds.
      */
+    @Override
     public long getDuration() {
         return mUnscaledDuration;
     }
@@ -608,6 +634,7 @@
         long seekTime = (long) (mDuration * fraction);
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         mStartTime = currentTime - seekTime;
+        mStartTimeCommitted = true; // do not allow start time to be compensated for jank
         if (mPlayingState != RUNNING) {
             mSeekFraction = fraction;
             mPlayingState = SEEKED;
@@ -644,7 +671,7 @@
      * @hide
      */
     @SuppressWarnings("unchecked")
-    protected static class AnimationHandler implements Runnable {
+    protected static class AnimationHandler {
         // The per-thread list of all active animations
         /** @hide */
         protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
@@ -667,6 +694,7 @@
 
         private final Choreographer mChoreographer;
         private boolean mAnimationScheduled;
+        private long mLastFrameTime;
 
         private AnimationHandler() {
             mChoreographer = Choreographer.getInstance();
@@ -679,7 +707,9 @@
             scheduleAnimation();
         }
 
-        private void doAnimationFrame(long frameTime) {
+        void doAnimationFrame(long frameTime) {
+            mLastFrameTime = frameTime;
+
             // mPendingAnimations holds any animations that have requested to be started
             // We're going to clear mPendingAnimations, but starting animation may
             // cause more to be added to the pending list (for example, if one animation
@@ -700,6 +730,7 @@
                     }
                 }
             }
+
             // Next, process animations currently sitting on the delayed queue, adding
             // them to the active animations if they are ready
             int numDelayedAnims = mDelayedAnims.size();
@@ -740,6 +771,9 @@
                 mEndingAnims.clear();
             }
 
+            // Schedule final commit for the frame.
+            mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mCommit, null);
+
             // If there are still active or delayed animations, schedule a future call to
             // onAnimate to process the next frame of the animations.
             if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
@@ -747,19 +781,37 @@
             }
         }
 
-        // Called by the Choreographer.
-        @Override
-        public void run() {
-            mAnimationScheduled = false;
-            doAnimationFrame(mChoreographer.getFrameTime());
+        void commitAnimationFrame(long frameTime) {
+            final long adjustment = frameTime - mLastFrameTime;
+            final int numAnims = mAnimations.size();
+            for (int i = 0; i < numAnims; ++i) {
+                mAnimations.get(i).commitAnimationFrame(adjustment);
+            }
         }
 
         private void scheduleAnimation() {
             if (!mAnimationScheduled) {
-                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
+                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
                 mAnimationScheduled = true;
             }
         }
+
+        // Called by the Choreographer.
+        final Runnable mAnimate = new Runnable() {
+            @Override
+            public void run() {
+                mAnimationScheduled = false;
+                doAnimationFrame(mChoreographer.getFrameTime());
+            }
+        };
+
+        // Called by the Choreographer.
+        final Runnable mCommit = new Runnable() {
+            @Override
+            public void run() {
+                commitAnimationFrame(mChoreographer.getFrameTime());
+            }
+        };
     }
 
     /**
@@ -768,6 +820,7 @@
      *
      * @return the number of milliseconds to delay running the animation
      */
+    @Override
     public long getStartDelay() {
         return mUnscaledStartDelay;
     }
@@ -778,6 +831,7 @@
 
      * @param startDelay The amount of the delay, in milliseconds
      */
+    @Override
     public void setStartDelay(long startDelay) {
         this.mStartDelay = (long)(startDelay * sDurationScale);
         mUnscaledStartDelay = startDelay;
@@ -1148,6 +1202,7 @@
             long currentPlayTime = currentTime - mStartTime;
             long timeLeft = mDuration - currentPlayTime;
             mStartTime = currentTime - timeLeft;
+            mStartTimeCommitted = true; // do not allow start time to be compensated for jank
             mReversing = !mReversing;
         } else if (mStarted) {
             end();
@@ -1254,9 +1309,9 @@
         }
         long deltaTime = currentTime - mDelayStartTime;
         if (deltaTime > mStartDelay) {
-            // startDelay ended - start the anim and record the
-            // mStartTime appropriately
-            mStartTime = currentTime - (deltaTime - mStartDelay);
+            // startDelay ended - start the anim and record the mStartTime appropriately
+            mStartTime = mDelayStartTime + mStartDelay;
+            mStartTimeCommitted = true; // do not allow start time to be compensated for jank
             mPlayingState = RUNNING;
             return true;
         }
@@ -1264,6 +1319,22 @@
     }
 
     /**
+     * Applies an adjustment to the animation to compensate for jank between when
+     * the animation first ran and when the frame was drawn.
+     */
+    void commitAnimationFrame(long adjustment) {
+        if (!mStartTimeCommitted) {
+            mStartTimeCommitted = true;
+            if (mPlayingState == RUNNING && adjustment > 0) {
+                mStartTime += adjustment;
+                if (DEBUG) {
+                    Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString());
+                }
+            }
+        }
+    }
+
+    /**
      * This internal function processes a single animation frame for a given animation. The
      * currentTime parameter is the timing pulse sent by the handler, used to calculate the
      * elapsed duration, and therefore
@@ -1303,6 +1374,8 @@
                     mCurrentIteration += (int) fraction;
                     fraction = fraction % 1f;
                     mStartTime += mDuration;
+                    // Note: We do not need to update the value of mStartTimeCommitted here
+                    // since we just added a duration offset.
                 } else {
                     done = true;
                     fraction = Math.min(fraction, 1.0f);
@@ -1334,6 +1407,7 @@
                 mStartTime = frameTime - seekTime;
                 mSeekFraction = -1;
             }
+            mStartTimeCommitted = false; // allow start time to be compensated for jank
         }
         if (mPaused) {
             if (mPauseTime < 0) {
@@ -1345,6 +1419,7 @@
             if (mPauseTime > 0) {
                 // Offset by the duration that the animation was paused
                 mStartTime += (frameTime - mPauseTime);
+                mStartTimeCommitted = false; // allow start time to be compensated for jank
             }
         }
         // The frame time might be before the start time during the first frame of
@@ -1406,6 +1481,12 @@
         anim.mInitialized = false;
         anim.mPlayingState = STOPPED;
         anim.mStartedDelay = false;
+        anim.mStarted = false;
+        anim.mRunning = false;
+        anim.mPaused = false;
+        anim.mResumed = false;
+        anim.mStartListenersCalled = false;
+
         PropertyValuesHolder[] oldValues = mValues;
         if (oldValues != null) {
             int numValues = oldValues.length;
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d143f8b..2b35cd4 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -269,45 +269,51 @@
      * all activities that are visible to the user. */
     public static final int PROCESS_STATE_TOP = 2;
 
+    /** @hide Process is hosting a foreground service. */
+    public static final int PROCESS_STATE_FOREGROUND_SERVICE = 3;
+
+    /** @hide Same as {@link #PROCESS_STATE_TOP} but while device is sleeping. */
+    public static final int PROCESS_STATE_TOP_SLEEPING = 4;
+
     /** @hide Process is important to the user, and something they are aware of. */
-    public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 3;
+    public static final int PROCESS_STATE_IMPORTANT_FOREGROUND = 5;
 
     /** @hide Process is important to the user, but not something they are aware of. */
-    public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 4;
+    public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 6;
 
     /** @hide Process is in the background running a backup/restore operation. */
-    public static final int PROCESS_STATE_BACKUP = 5;
+    public static final int PROCESS_STATE_BACKUP = 7;
 
     /** @hide Process is in the background, but it can't restore its state so we want
      * to try to avoid killing it. */
-    public static final int PROCESS_STATE_HEAVY_WEIGHT = 6;
+    public static final int PROCESS_STATE_HEAVY_WEIGHT = 8;
 
     /** @hide Process is in the background running a service.  Unlike oom_adj, this level
      * is used for both the normal running in background state and the executing
      * operations state. */
-    public static final int PROCESS_STATE_SERVICE = 7;
+    public static final int PROCESS_STATE_SERVICE = 9;
 
     /** @hide Process is in the background running a receiver.   Note that from the
      * perspective of oom_adj receivers run at a higher foreground level, but for our
      * prioritization here that is not necessary and putting them below services means
      * many fewer changes in some process states as they receive broadcasts. */
-    public static final int PROCESS_STATE_RECEIVER = 8;
+    public static final int PROCESS_STATE_RECEIVER = 10;
 
     /** @hide Process is in the background but hosts the home activity. */
-    public static final int PROCESS_STATE_HOME = 9;
+    public static final int PROCESS_STATE_HOME = 11;
 
     /** @hide Process is in the background but hosts the last shown activity. */
-    public static final int PROCESS_STATE_LAST_ACTIVITY = 10;
+    public static final int PROCESS_STATE_LAST_ACTIVITY = 12;
 
     /** @hide Process is being cached for later use and contains activities. */
-    public static final int PROCESS_STATE_CACHED_ACTIVITY = 11;
+    public static final int PROCESS_STATE_CACHED_ACTIVITY = 13;
 
     /** @hide Process is being cached for later use and is a client of another cached
      * process that contains activities. */
-    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 12;
+    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 14;
 
     /** @hide Process is being cached for later use and is empty. */
-    public static final int PROCESS_STATE_CACHED_EMPTY = 13;
+    public static final int PROCESS_STATE_CACHED_EMPTY = 15;
 
     /** @hide requestType for assist context: only basic information. */
     public static final int ASSIST_CONTEXT_BASIC = 0;
@@ -2064,7 +2070,7 @@
                 return ActivityManager.RunningAppProcessInfo.IMPORTANCE_CANT_SAVE_STATE;
             } else if (procState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
                 return ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
-            } else if (procState >= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
+            } else if (procState >= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
                 return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
             } else {
                 return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
@@ -2682,6 +2688,47 @@
     }
 
     /**
+     * Request that the system start watching for the calling process to exceed a pss
+     * size as given here.  Once called, the system will look for any occassions where it
+     * sees the associated process with a larger pss size and, when this happens, automatically
+     * pull a heap dump from it and allow the user to share the data.  Note that this request
+     * continues running even if the process is killed and restarted.  To remove the watch,
+     * use {@link #clearWatchHeapLimit()}.
+     *
+     * <p>This API only work if running on a debuggable (userdebug or eng) build.</p>
+     *
+     * <p>Callers can optionally implement {@link #ACTION_REPORT_HEAP_LIMIT} to directly
+     * handle heap limit reports themselves.</p>
+     *
+     * @param pssSize The size in bytes to set the limit at.
+     */
+    public void setWatchHeapLimit(long pssSize) {
+        try {
+            ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, pssSize,
+                    mContext.getPackageName());
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Action an app can implement to handle reports from {@link #setWatchHeapLimit(long)}.
+     * If your package has an activity handling this action, it will be launched with the
+     * heap data provided to it the same way as {@link Intent#ACTION_SEND}.  Note that to
+     * match the activty must support this action and a MIME type of "*&#47;*".
+     */
+    public static final String ACTION_REPORT_HEAP_LIMIT = "android.app.action.REPORT_HEAP_LIMIT";
+
+    /**
+     * Clear a heap watch limit previously set by {@link #setWatchHeapLimit(long)}.
+     */
+    public void clearWatchHeapLimit() {
+        try {
+            ActivityManagerNative.getDefault().setDumpHeapDebugLimit(null, 0, 0, null);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * @hide
      */
     public void startLockTaskMode(int taskId) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1484af8..f63d13c 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2427,8 +2427,10 @@
         case SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String procName = data.readString();
+            int uid = data.readInt();
             long maxMemSize = data.readLong();
-            setDumpHeapDebugLimit(procName, maxMemSize);
+            String reportPackage = data.readString();
+            setDumpHeapDebugLimit(procName, uid, maxMemSize, reportPackage);
             reply.writeNoException();
             return true;
         }
@@ -2450,6 +2452,15 @@
             reply.writeNoException();
             return true;
         }
+
+        case UPDATE_LOCK_TASK_PACKAGES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int userId = data.readInt();
+            String[] packages = data.readStringArray();
+            updateLockTaskPackages(userId, packages);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -5644,12 +5655,15 @@
     }
 
     @Override
-    public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException {
+    public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
+            String reportPackage) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeString(processName);
+        data.writeInt(uid);
         data.writeLong(maxMemSize);
+        data.writeString(reportPackage);
         mRemote.transact(SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
@@ -5682,5 +5696,18 @@
         reply.recycle();
     }
 
+    @Override
+    public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(userId);
+        data.writeStringArray(packages);
+        mRemote.transact(UPDATE_LOCK_TASK_PACKAGES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4880db1..3b96fd5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -94,7 +94,7 @@
 import android.view.Window;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptCacheDir;
 import android.security.AndroidKeyStoreProvider;
 
 import com.android.internal.app.IVoiceInteractor;
@@ -254,18 +254,21 @@
         }
     }
 
+    static final class AcquiringProviderRecord {
+        IActivityManager.ContentProviderHolder holder;
+        boolean acquiring = true;
+        int requests = 1;
+    }
+
     // The lock of mProviderMap protects the following variables.
-    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
-        = new ArrayMap<ProviderKey, ProviderClientRecord>();
-    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
-        = new ArrayMap<IBinder, ProviderRefCount>();
-    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders
-        = new ArrayMap<IBinder, ProviderClientRecord>();
-    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
-            = new ArrayMap<ComponentName, ProviderClientRecord>();
+    final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<>();
+    final ArrayMap<ProviderKey, AcquiringProviderRecord> mAcquiringProviderMap = new ArrayMap<>();
+    final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap = new ArrayMap<>();
+    final ArrayMap<IBinder, ProviderClientRecord> mLocalProviders = new ArrayMap<>();
+    final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName = new ArrayMap<>();
 
     final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
-        = new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
+            = new ArrayMap<>();
 
     final GcIdler mGcIdler = new GcIdler();
     boolean mGcIdlerScheduled = false;
@@ -345,7 +348,7 @@
         }
     }
 
-    final class ProviderClientRecord {
+    static final class ProviderClientRecord {
         final String[] mNames;
         final IContentProvider mProvider;
         final ContentProvider mLocalProvider;
@@ -3211,7 +3214,7 @@
                 if (cv == null) {
                     mThumbnailCanvas = cv = new Canvas();
                 }
-    
+
                 cv.setBitmap(thumbnail);
                 if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
                     mAvailThumbnailBitmap = thumbnail;
@@ -3513,12 +3516,12 @@
 
     private void handleWindowVisibility(IBinder token, boolean show) {
         ActivityClientRecord r = mActivities.get(token);
-        
+
         if (r == null) {
             Log.w(TAG, "handleWindowVisibility: no activity for token " + token);
             return;
         }
-        
+
         if (!show && !r.stopped) {
             performStopActivityInner(r, null, show, false);
         } else if (show && r.stopped) {
@@ -3950,10 +3953,10 @@
                 }
             }
         }
-        
+
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
                 + tmp.token + ": changedConfig=" + changedConfig);
-        
+
         // If there was a pending configuration change, execute it first.
         if (changedConfig != null) {
             mCurDefaultDisplayDpi = changedConfig.densityDpi;
@@ -4151,7 +4154,7 @@
             if (config == null) {
                 return;
             }
-            
+
             if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
                     + config);
 
@@ -4289,7 +4292,7 @@
         ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
                 hasPkgInfo);
     }
-        
+
     final void handleLowMemory() {
         ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
 
@@ -4336,10 +4339,10 @@
             String[] packages = getPackageManager().getPackagesForUid(uid);
 
             // If there are several packages in this application we won't
-            // initialize the graphics disk caches 
+            // initialize the graphics disk caches
             if (packages != null && packages.length == 1) {
                 HardwareRenderer.setupDiskCache(cacheDir);
-                RenderScript.setupDiskCache(cacheDir);
+                RenderScriptCacheDir.setupDiskCache(cacheDir);
             }
         } catch (RemoteException e) {
             // Ignore
@@ -4693,22 +4696,57 @@
 
     public final IContentProvider acquireProvider(
             Context c, String auth, int userId, boolean stable) {
-        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
+        final ProviderKey key = new ProviderKey(auth, userId);
+        final IContentProvider provider = acquireExistingProvider(c, key, stable);
         if (provider != null) {
             return provider;
         }
+        AcquiringProviderRecord r;
+        boolean first = false;
+        synchronized (mAcquiringProviderMap) {
+            r = mAcquiringProviderMap.get(key);
+            if (r == null) {
+                r = new AcquiringProviderRecord();
+                mAcquiringProviderMap.put(key, r);
+                first = true;
+            } else {
+                r.requests++;
+            }
+        }
 
-        // There is a possible race here.  Another thread may try to acquire
-        // the same provider at the same time.  When this happens, we want to ensure
-        // that the first one wins.
-        // Note that we cannot hold the lock while acquiring and installing the
-        // provider since it might take a long time to run and it could also potentially
-        // be re-entrant in the case where the provider is in the same process.
         IActivityManager.ContentProviderHolder holder = null;
-        try {
-            holder = ActivityManagerNative.getDefault().getContentProvider(
-                    getApplicationThread(), auth, userId, stable);
-        } catch (RemoteException ex) {
+        if (first) {
+            // Multiple threads may try to acquire the same provider at the same time.
+            // When this happens, we only let the first one really gets provider.
+            // Other threads just wait for its result.
+            // Note that we cannot hold the lock while acquiring and installing the
+            // provider since it might take a long time to run and it could also potentially
+            // be re-entrant in the case where the provider is in the same process.
+            try {
+                holder = ActivityManagerNative.getDefault().getContentProvider(
+                        getApplicationThread(), auth, userId, stable);
+            } catch (RemoteException ex) {
+            }
+            synchronized (r) {
+                r.holder = holder;
+                r.acquiring = false;
+                r.notifyAll();
+            }
+        } else {
+            synchronized (r) {
+                while (r.acquiring) {
+                    try {
+                        r.wait();
+                    } catch (InterruptedException e) {
+                    }
+                }
+                holder = r.holder;
+            }
+        }
+        synchronized (mAcquiringProviderMap) {
+            if (--r.requests == 0) {
+                mAcquiringProviderMap.remove(key);
+            }
         }
         if (holder == null) {
             Slog.e(TAG, "Failed to find provider info for " + auth);
@@ -4792,8 +4830,12 @@
 
     public final IContentProvider acquireExistingProvider(
             Context c, String auth, int userId, boolean stable) {
+        return acquireExistingProvider(c, new ProviderKey(auth, userId), stable);
+    }
+
+    final IContentProvider acquireExistingProvider(
+            Context c, ProviderKey key, boolean stable) {
         synchronized (mProviderMap) {
-            final ProviderKey key = new ProviderKey(auth, userId);
             final ProviderClientRecord pr = mProviderMap.get(key);
             if (pr == null) {
                 return null;
@@ -4804,7 +4846,7 @@
             if (!jBinder.isBinderAlive()) {
                 // The hosting process of the provider has died; we can't
                 // use this one.
-                Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+                Log.i(TAG, "Acquiring provider " + key.authority + " for user " +  key.userId
                         + ": existing object's process dead");
                 handleUnstableProviderDiedLocked(jBinder, true);
                 return null;
@@ -5126,18 +5168,12 @@
                     if (DEBUG_PROVIDER) {
                         Slog.v(TAG, "installProvider: lost the race, updating ref count");
                     }
-                    // We need to transfer our new reference to the existing
-                    // ref count, releasing the old one...  but only if
-                    // release is needed (that is, it is not running in the
-                    // system process).
+                    // The provider has already been installed, so we need
+                    // to increase reference count to the existing one, but
+                    // only if release is needed (that is, it is not running
+                    // in the system process or local to the process).
                     if (!noReleaseNeeded) {
                         incProviderRefLocked(prc, stable);
-                        try {
-                            ActivityManagerNative.getDefault().removeContentProvider(
-                                    holder.connection, stable);
-                        } catch (RemoteException e) {
-                            //do nothing content provider object is dead any way
-                        }
                     }
                 } else {
                     ProviderClientRecord client = installProviderAuthoritiesLocked(
@@ -5231,7 +5267,7 @@
                         if (mPendingConfiguration == null ||
                                 mPendingConfiguration.isOtherSeqNewer(newConfig)) {
                             mPendingConfiguration = newConfig;
-                            
+
                             sendMessage(H.CONFIGURATION_CHANGED, newConfig);
                         }
                     }
@@ -5286,19 +5322,25 @@
 
         private DropBoxManager dropBox;
 
-        public DropBoxReporter() {
-            dropBox = (DropBoxManager) getSystemContext().getSystemService(Context.DROPBOX_SERVICE);
-        }
+        public DropBoxReporter() {}
 
         @Override
         public void addData(String tag, byte[] data, int flags) {
+            ensureInitialized();
             dropBox.addData(tag, data, flags);
         }
 
         @Override
         public void addText(String tag, String data) {
+            ensureInitialized();
             dropBox.addText(tag, data);
         }
+
+        private synchronized void ensureInitialized() {
+            if (dropBox == null) {
+                dropBox = (DropBoxManager) getSystemContext().getSystemService(Context.DROPBOX_SERVICE);
+            }
+        }
     }
 
     public static void main(String[] args) {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 5dd02ae..179957d 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -115,6 +115,40 @@
     /** @hide */
     public static final long WINDOW_HEURISTIC = -1;
 
+    /**
+     * Flag for alarms: this is to be a stand-alone alarm, that should not be batched with
+     * other alarms.
+     * @hide
+     */
+    public static final int FLAG_STANDALONE = 1<<0;
+
+    /**
+     * Flag for alarms: this alarm would like to wake the device even if it is idle.  This
+     * is, for example, an alarm for an alarm clock.
+     * @hide
+     */
+    public static final int FLAG_WAKE_FROM_IDLE = 1<<1;
+
+    /**
+     * Flag for alarms: this alarm would like to still execute even if the device is
+     * idle.  This won't bring the device out of idle, just allow this specific alarm to
+     * run.  Note that this means the actual time this alarm goes off can be inconsistent
+     * with the time of non-allow-while-idle alarms (it could go earlier than the time
+     * requested by another alarm).
+     *
+     * @hide
+     */
+    public static final int FLAG_ALLOW_WHILE_IDLE = 1<<2;
+
+    /**
+     * Flag for alarms: this alarm marks the point where we would like to come out of idle
+     * mode.  It may be moved by the alarm manager to match the first wake-from-idle alarm.
+     * Scheduling an alarm with this flag puts the alarm manager in to idle mode, where it
+     * avoids scheduling any further alarms until the marker alarm is executed.
+     * @hide
+     */
+    public static final int FLAG_IDLE_UNTIL = 1<<3;
+
     private final IAlarmManager mService;
     private final boolean mAlwaysExact;
 
@@ -204,7 +238,7 @@
      * @see #RTC_WAKEUP
      */
     public void set(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, legacyExactLength(), 0, operation, null, null);
+        setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null);
     }
 
     /**
@@ -265,7 +299,8 @@
      */
     public void setRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, operation, null, null);
+        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation, null,
+                null);
     }
 
     /**
@@ -315,7 +350,7 @@
      */
     public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
             PendingIntent operation) {
-        setImpl(type, windowStartMillis, windowLengthMillis, 0, operation, null, null);
+        setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, operation, null, null);
     }
 
     /**
@@ -353,7 +388,16 @@
      * @see #RTC_WAKEUP
      */
     public void setExact(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, operation, null, null);
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, operation, null, null);
+    }
+
+    /**
+     * Schedule an idle-until alarm, which will keep the alarm manager idle until
+     * the given time.
+     * @hide
+     */
+    public void setIdleUntil(int type, long triggerAtMillis, PendingIntent operation) {
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, operation, null, null);
     }
 
     /**
@@ -381,18 +425,19 @@
      * @see android.content.Intent#filterEquals
      */
     public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {
-        setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, operation, null, info);
+        setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, 0, operation, null, info);
     }
 
     /** @hide */
     @SystemApi
     public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
             PendingIntent operation, WorkSource workSource) {
-        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, operation, workSource, null);
+        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, operation, workSource,
+                null);
     }
 
     private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
-            PendingIntent operation, WorkSource workSource, AlarmClockInfo alarmClock) {
+            int flags, PendingIntent operation, WorkSource workSource, AlarmClockInfo alarmClock) {
         if (triggerAtMillis < 0) {
             /* NOTYET
             if (mAlwaysExact) {
@@ -405,7 +450,7 @@
         }
 
         try {
-            mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
+            mService.set(type, triggerAtMillis, windowMillis, intervalMillis, flags, operation,
                     workSource, alarmClock);
         } catch (RemoteException ex) {
         }
@@ -506,7 +551,7 @@
      */
     public void setInexactRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, operation, null, null);
+        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null, null);
     }
     
     /**
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 3e545f9..abe12dc 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -22,6 +22,7 @@
 import android.annotation.AttrRes;
 import android.annotation.DrawableRes;
 import android.annotation.StringRes;
+import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.database.Cursor;
@@ -134,6 +135,7 @@
      * {@code context}'s theme.
      *
      * @param context the parent context
+     * @see android.R.styleable#Theme_alertDialogTheme
      */
     protected AlertDialog(Context context) {
         this(context, 0);
@@ -155,6 +157,7 @@
      * {@code context}'s theme.
      *
      * @param context the parent context
+     * @see android.R.styleable#Theme_alertDialogTheme
      */
     protected AlertDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
         this(context, 0);
@@ -187,9 +190,15 @@
      * @param themeResId the resource ID of the theme against which to inflate
      *                   this dialog, or {@code 0} to use the parent
      *                   {@code context}'s default alert dialog theme
+     * @see android.R.styleable#Theme_alertDialogTheme
      */
-    protected AlertDialog(Context context, @AttrRes int themeResId) {
-        super(context, resolveDialogTheme(context, themeResId));
+    protected AlertDialog(Context context, @StyleRes int themeResId) {
+        this(context, themeResId, true);
+    }
+
+    AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
+        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
+                createContextThemeWrapper);
 
         mWindow.alwaysReadCloseOnTouchAttr();
         mAlert = new AlertController(getContext(), this, getWindow());
@@ -428,7 +437,6 @@
 
     public static class Builder {
         private final AlertController.AlertParams P;
-        private int mThemeResId;
 
         /**
          * Creates a builder for an alert dialog that uses the default alert
@@ -473,7 +481,6 @@
         public Builder(Context context, int themeResId) {
             P = new AlertController.AlertParams(new ContextThemeWrapper(
                     context, resolveDialogTheme(context, themeResId)));
-            mThemeResId = themeResId;
         }
 
         /**
@@ -1075,7 +1082,7 @@
          * create and display the dialog.
          */
         public AlertDialog create() {
-            final AlertDialog dialog = new AlertDialog(P.mContext, mThemeResId);
+            final AlertDialog dialog = new AlertDialog(P.mContext);
             P.apply(dialog.mAlert);
             dialog.setCancelable(P.mCancelable);
             if (P.mCancelable) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4bd2332..381c20c 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -208,8 +208,12 @@
     public static final int OP_ACTIVATE_VPN = 47;
     /** @hide Access the WallpaperManagerAPI to write wallpapers. */
     public static final int OP_WRITE_WALLPAPER = 48;
+    /** @hide Received the assist structure from an app. */
+    public static final int OP_ASSIST_STRUCTURE = 49;
+    /** @hide Received a screenshot from assist. */
+    public static final int OP_ASSIST_SCREENSHOT = 50;
     /** @hide */
-    public static final int _NUM_OP = 49;
+    public static final int _NUM_OP = 51;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION =
@@ -288,6 +292,8 @@
             OP_PROJECT_MEDIA,
             OP_ACTIVATE_VPN,
             OP_WRITE_WALLPAPER,
+            OP_ASSIST_STRUCTURE,
+            OP_ASSIST_SCREENSHOT,
     };
 
     /**
@@ -344,6 +350,8 @@
             null,
             OPSTR_ACTIVATE_VPN,
             null,
+            null,
+            null,
     };
 
     /**
@@ -400,6 +408,8 @@
             "PROJECT_MEDIA",
             "ACTIVATE_VPN",
             "WRITE_WALLPAPER",
+            "ASSIST_STRUCTURE",
+            "ASSIST_SCREENSHOT"
     };
 
     /**
@@ -456,6 +466,8 @@
             null, // no permission for projecting media
             null, // no permission for activating vpn
             null, // no permission for supporting wallpaper
+            null, // no permission for receiving assist structure
+            null, // no permission for receiving assist screenshot
     };
 
     /**
@@ -513,6 +525,8 @@
             null, //PROJECT_MEDIA
             UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN
             UserManager.DISALLOW_WALLPAPER, // WRITE_WALLPAPER
+            null, // ASSIST_STRUCTURE
+            null, // ASSIST_SCREENSHOT
     };
 
     /**
@@ -569,6 +583,8 @@
             false, //PROJECT_MEDIA
             false, //ACTIVATE_VPN
             false, //WALLPAPER
+            false, //ASSIST_STRUCTURE
+            false, //ASSIST_SCREENSHOT
     };
 
     /**
@@ -624,6 +640,8 @@
             AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
             AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
             AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
+            AppOpsManager.MODE_ALLOWED,
     };
 
     /**
@@ -683,6 +701,8 @@
             false,
             false,
             false,
+            false,
+            false,
     };
 
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 6c2511e..8692336 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -235,10 +235,13 @@
         dest.writeString(processName);
         dest.writeLong(time);
         dest.writeInt(systemApp ? 1 : 0);
+        dest.writeInt(crashInfo != null ? 1 : 0);
 
         switch (type) {
             case TYPE_CRASH:
-                crashInfo.writeToParcel(dest, flags);
+                if (crashInfo != null) {
+                    crashInfo.writeToParcel(dest, flags);
+                }
                 break;
             case TYPE_ANR:
                 anrInfo.writeToParcel(dest, flags);
@@ -259,10 +262,11 @@
         processName = in.readString();
         time = in.readLong();
         systemApp = in.readInt() == 1;
+        boolean hasCrashInfo = in.readInt() == 1;
 
         switch (type) {
             case TYPE_CRASH:
-                crashInfo = new CrashInfo(in);
+                crashInfo = hasCrashInfo ? new CrashInfo(in) : null;
                 anrInfo = null;
                 batteryInfo = null;
                 runningServiceInfo = null;
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 6ec5457..9ddfd88 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -62,19 +62,19 @@
 import android.net.Uri;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.view.Display;
-import android.os.SystemProperties;
+
+import dalvik.system.VMRuntime;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.UserIcons;
 
-import dalvik.system.VMRuntime;
-
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -1349,6 +1349,36 @@
     }
 
     @Override
+    public List<IntentFilter> getAllIntentFilters(String packageName) {
+        try {
+            return mPM.getAllIntentFilters(packageName);
+        } catch (RemoteException e) {
+            // Should never happen!
+            return null;
+        }
+    }
+
+    @Override
+    public String getDefaultBrowserPackageName(int userId) {
+        try {
+            return mPM.getDefaultBrowserPackageName(userId);
+        } catch (RemoteException e) {
+            // Should never happen!
+            return null;
+        }
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        try {
+            return mPM.setDefaultBrowserPackageName(packageName, userId);
+        } catch (RemoteException e) {
+            // Should never happen!
+            return false;
+        }
+    }
+
+    @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
         try {
@@ -1363,7 +1393,17 @@
         try {
             mPM.movePackage(packageName, observer, flags);
         } catch (RemoteException e) {
-            // Should never happen!
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    @Override
+    public void movePackageAndData(String packageName, String volumeUuid,
+            IPackageMoveObserver observer) {
+        try {
+            mPM.movePackageAndData(packageName, volumeUuid, observer);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
         }
     }
 
diff --git a/core/java/android/app/AssistAction.java b/core/java/android/app/AssistAction.java
new file mode 100644
index 0000000..eb33542
--- /dev/null
+++ b/core/java/android/app/AssistAction.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Helper class for building a {@link Bundle} representing an action being performed by the user,
+ * to be included in the Bundle generated by {@link Activity#onProvideAssistData}.
+ *
+ * @see Activity#onProvideAssistData
+ */
+public final class AssistAction {
+
+    /**
+     * Key name for the Bundle containing the schema.org representation of
+     * an action performed, and should be stored in the Bundle generated by
+     * {@link Activity#onProvideAssistData}.
+     */
+    public static final String ASSIST_ACTION_KEY = "android:assist_action";
+
+    /** Bundle key to specify the schema.org ID of the content. */
+    public static final String KEY_ID = "@id";
+
+    /** Bundle key to specify the schema.org type of the content. */
+    public static final String KEY_TYPE = "@type";
+
+    /** Bundle key to specify the name of the content. */
+    public static final String KEY_NAME = "name";
+
+    /** Bundle key to specify the description of the content. */
+    public static final String KEY_DESCRIPTION = "description";
+
+    /** Bundle key to specify the URL of the content. */
+    public static final String KEY_URL = "url";
+
+    /** Bundle key to specify the object of an action. */
+    public static final String KEY_ACTION_OBJECT = "object";
+
+    /** Bundle key to specify the action's status. */
+    public static final String KEY_ACTION_STATUS = "actionStatus";
+
+    /** The act of editing by adding an object to a collection. */
+    public static final String TYPE_ADD_ACTION = "AddAction";
+
+    /** The act of bookmarking an object. */
+    public static final String TYPE_BOOKMARK_ACTION = "BookmarkAction";
+
+    /** The act of liking an object. */
+    public static final String TYPE_LIKE_ACTION = "LikeAction";
+
+    /** The act of consuming audio content. */
+    public static final String TYPE_LISTEN_ACTION = "ListenAction";
+
+    /** The act of consuming static visual content. */
+    public static final String TYPE_VIEW_ACTION = "ViewAction";
+
+    /** The act of expressing a desire about the object. */
+    public static final String TYPE_WANT_ACTION = "WantAction";
+
+    /** The act of watching an object. */
+    public static final String TYPE_WATCH_ACTION = "WatchAction";
+
+    /** The status of an active action. */
+    public static final String STATUS_TYPE_ACTIVE = "ActiveActionStatus";
+
+    /** The status of a completed action. */
+    public static final String STATUS_TYPE_COMPLETED = "CompletedActionStatus";
+
+    private AssistAction() {
+    }
+
+    /**
+     * Update the Bundle passed into {@link Activity#onProvideAssistData} with the action Bundle,
+     * built with {@link ActionBuilder}.
+     *
+     * @param assistDataBundle The Bundle provided to {@link Activity#onProvideAssistData}.
+     * @param actionBundle The Bundle representing an schema.org action.
+     */
+    public static void updateAssistData(Bundle assistDataBundle, Bundle actionBundle) {
+        Preconditions.checkNotNull(assistDataBundle);
+        Preconditions.checkNotNull(actionBundle);
+
+        Preconditions.checkNotNull(actionBundle.getString(KEY_TYPE),
+                "The '@type' property is required in the provided actionBundle");
+        assistDataBundle.putParcelable(ASSIST_ACTION_KEY, actionBundle);
+    }
+
+    /**
+     * Builds a {@link Bundle} representing a schema.org entity.
+     */
+    public static final class ThingBuilder {
+        private final Bundle mBundle;
+
+        public ThingBuilder() {
+            mBundle = new Bundle();
+        }
+
+        /**
+         * Sets the name of the content.
+         *
+         * @param name The name of the content.
+         */
+        public ThingBuilder setName(@Nullable String name) {
+            set(KEY_NAME, name);
+            return this;
+        }
+
+        /**
+         * Sets the app URI of the content.
+         *
+         * @param uri The app URI of the content.
+         */
+        public ThingBuilder setUrl(@Nullable Uri uri) {
+            if (uri != null) {
+                set(KEY_URL, uri.toString());
+            }
+            return this;
+        }
+
+        /**
+         * Sets the ID of the content.
+         *
+         * @param id Set the ID of the content.
+         */
+        public ThingBuilder setId(@Nullable String id) {
+            set(KEY_ID, id);
+            return this;
+        }
+
+        /**
+        * Sets the schema.org type of the content.
+        *
+        * @param type The schema.org type.
+        */
+        public ThingBuilder setType(@Nullable String type) {
+            set(KEY_TYPE, type);
+            return this;
+        }
+
+        /**
+         * Sets the optional description of the content.
+         *
+         * @param description The description of the content.
+         */
+        public ThingBuilder setDescription(@Nullable String description) {
+            set(KEY_DESCRIPTION, description);
+            return this;
+        }
+
+        /**
+         * Sets a property of the content.
+         *
+         * @param key The schema.org property. Must not be null.
+         * @param value The value of the schema.org property.
+         *              If null, the value will be ignored.
+         */
+        public ThingBuilder set(@NonNull String key, @Nullable String value) {
+            if (value != null) {
+                mBundle.putString(key, value);
+            }
+            return this;
+        }
+
+        /**
+         * Sets a property of the content.
+         *
+         * @param key The schema.org property. Must not be null.
+         * @param value The value of the schema.org property represented as a bundle.
+         *              If null, the value will be ignored.
+         */
+        public ThingBuilder set(@NonNull String key, @Nullable Bundle value) {
+            if (value != null) {
+                mBundle.putParcelable(key, value);
+            }
+            return this;
+        }
+
+        /**
+         * Build the {@link Bundle} object representing the schema.org entity.
+         */
+        public Bundle build() {
+            return mBundle;
+        }
+    }
+
+    /**
+     * Builds a {@link Bundle} representing a schema.org action.
+     */
+    public static final class ActionBuilder {
+        private final Bundle mBundle;
+
+        public ActionBuilder() {
+            mBundle = new Bundle();
+        }
+
+        /**
+         * Sets the schema.org type of the action.
+         *
+         * @param type The schema.org type.
+         */
+        public ActionBuilder setType(@Nullable String type) {
+            set(KEY_TYPE, type);
+            return this;
+        }
+
+        /**
+         * Sets the schema.org object of the action.
+         *
+         * @param object The schema.org object of the action.
+         */
+        public ActionBuilder setObject(@Nullable Bundle object) {
+            set(KEY_ACTION_OBJECT, object);
+            return this;
+        }
+
+        /**
+         * Sets a property of the action.
+         *
+         * @param key The schema.org property. Must not be null.
+         * @param value The value of the schema.org property.
+         *              If null, the value will be ignored.
+         */
+        public ActionBuilder set(@NonNull String key, @Nullable String value) {
+            if (value != null) {
+                mBundle.putString(key, value);
+            }
+            return this;
+        }
+
+        /**
+         * Sets a property of the action.
+         *
+         * @param key The schema.org property. Must not be null.
+         * @param value The value of the schema.org property represented as a bundle.
+         *              If null, the value will be ignored.
+         */
+        public ActionBuilder set(@NonNull String key, @Nullable Bundle value) {
+            if (value != null) {
+                mBundle.putParcelable(key, value);
+            }
+            return this;
+        }
+
+        /**
+         * Build the {@link Bundle} object representing the schema.org action.
+         */
+        public Bundle build() {
+            if (TextUtils.isEmpty(mBundle.getString(KEY_TYPE, null))) {
+                // Defaults to the base action type http://schema.org/Action.
+                setType("Action");
+            }
+
+            return mBundle;
+        }
+    }
+}
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
index ace4af7..cb1a3f5 100644
--- a/core/java/android/app/AssistContent.java
+++ b/core/java/android/app/AssistContent.java
@@ -51,7 +51,7 @@
     /**
      * Sets the Intent associated with the content, describing the current top-level context of
      * the activity.  If this contains a reference to a piece of data related to the activity,
-     * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibilty
+     * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibility
      * service can access it.
      */
     public void setIntent(Intent intent) {
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
index c435ccb..1e159a3 100644
--- a/core/java/android/app/AssistStructure.java
+++ b/core/java/android/app/AssistStructure.java
@@ -17,24 +17,25 @@
 package android.app;
 
 import android.content.ComponentName;
-import android.content.res.Resources;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Typeface;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PooledStringReader;
 import android.os.PooledStringWriter;
+import android.os.RemoteException;
+import android.os.SystemClock;
 import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewAssistStructure;
-import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.view.WindowManagerGlobal;
-import android.widget.Checkable;
 
 import java.util.ArrayList;
 
@@ -52,111 +53,49 @@
      */
     public static final String ASSIST_KEY = "android:assist_structure";
 
-    final ComponentName mActivityComponent;
+    boolean mHaveData;
+
+    ComponentName mActivityComponent;
 
     final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
 
-    ViewAssistStructureImpl mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
-    Bundle mTmpExtras = new Bundle();
+    final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
 
-    final static class ViewAssistStructureImpl extends ViewAssistStructure {
-        CharSequence mText;
-        int mTextSelectionStart = -1;
-        int mTextSelectionEnd = -1;
-        int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED;
-        int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED;
-        float mTextSize = 0;
-        int mTextStyle = 0;
-        CharSequence mHint;
+    SendChannel mSendChannel;
+    IBinder mReceiveChannel;
 
-        @Override
-        public void setText(CharSequence text) {
-            mText = text;
-            mTextSelectionStart = mTextSelectionEnd = -1;
-        }
+    Rect mTmpRect = new Rect();
 
-        @Override
-        public void setText(CharSequence text, int selectionStart, int selectionEnd) {
-            mText = text;
-            mTextSelectionStart = selectionStart;
-            mTextSelectionEnd = selectionEnd;
-        }
+    static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
+    static final String DESCRIPTOR = "android.app.AssistStructure";
 
-        @Override
-        public void setTextPaint(TextPaint paint) {
-            mTextColor = paint.getColor();
-            mTextBackgroundColor = paint.bgColor;
-            mTextSize = paint.getTextSize();
-            mTextStyle = 0;
-            Typeface tf = paint.getTypeface();
-            if (tf != null) {
-                if (tf.isBold()) {
-                    mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
-                }
-                if (tf.isItalic()) {
-                    mTextStyle |= ViewNode.TEXT_STYLE_ITALIC;
-                }
+    final class SendChannel extends Binder {
+        @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                throws RemoteException {
+            if (code == TRANSACTION_XFER) {
+                data.enforceInterface(DESCRIPTOR);
+                writeContentToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+                return true;
+            } else {
+                return super.onTransact(code, data, reply, flags);
             }
-            int pflags = paint.getFlags();
-            if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
-                mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
-            }
-            if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) {
-                mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE;
-            }
-            if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
-                mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU;
-            }
-        }
-
-        @Override
-        public void setHint(CharSequence hint) {
-            mHint = hint;
-        }
-
-        @Override
-        public CharSequence getText() {
-            return mText;
-        }
-
-        @Override
-        public int getTextSelectionStart() {
-            return mTextSelectionStart;
-        }
-
-        @Override
-        public int getTextSelectionEnd() {
-            return mTextSelectionEnd;
-        }
-
-        @Override
-        public CharSequence getHint() {
-            return mHint;
         }
     }
 
-    final static class ViewNodeTextImpl {
-        final CharSequence mText;
-        final int mTextSelectionStart;
-        final int mTextSelectionEnd;
+    final static class ViewNodeText {
+        CharSequence mText;
+        int mTextSelectionStart;
+        int mTextSelectionEnd;
         int mTextColor;
         int mTextBackgroundColor;
         float mTextSize;
         int mTextStyle;
-        final String mHint;
+        String mHint;
 
-        ViewNodeTextImpl(ViewAssistStructureImpl data) {
-            mText = data.mText;
-            mTextSelectionStart = data.mTextSelectionStart;
-            mTextSelectionEnd = data.mTextSelectionEnd;
-            mTextColor = data.mTextColor;
-            mTextBackgroundColor = data.mTextBackgroundColor;
-            mTextSize = data.mTextSize;
-            mTextStyle = data.mTextStyle;
-            mHint = data.mHint != null ? data.mHint.toString() : null;
+        ViewNodeText() {
         }
 
-        ViewNodeTextImpl(Parcel in) {
+        ViewNodeText(Parcel in) {
             mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             mTextSelectionStart = in.readInt();
             mTextSelectionEnd = in.readInt();
@@ -199,7 +138,9 @@
             mWidth = rect.width();
             mHeight = rect.height();
             mTitle = root.getTitle();
-            mRoot = new ViewNode(assist, view);
+            mRoot = new ViewNode();
+            ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
+            view.dispatchProvideAssistStructure(builder);
         }
 
         WindowNode(Parcel in, PooledStringReader preader) {
@@ -260,16 +201,16 @@
         public static final int TEXT_STYLE_UNDERLINE = 1<<2;
         public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
 
-        final int mId;
-        final String mIdPackage;
-        final String mIdType;
-        final String mIdEntry;
-        final int mX;
-        final int mY;
-        final int mScrollX;
-        final int mScrollY;
-        final int mWidth;
-        final int mHeight;
+        int mId;
+        String mIdPackage;
+        String mIdType;
+        String mIdEntry;
+        int mX;
+        int mY;
+        int mScrollX;
+        int mScrollY;
+        int mWidth;
+        int mHeight;
 
         static final int FLAGS_DISABLED = 0x00000001;
         static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
@@ -283,104 +224,17 @@
         static final int FLAGS_CLICKABLE = 0x00004000;
         static final int FLAGS_LONG_CLICKABLE = 0x00200000;
 
-        final int mFlags;
+        int mFlags;
 
-        final String mClassName;
-        final CharSequence mContentDescription;
+        String mClassName;
+        CharSequence mContentDescription;
 
-        final ViewNodeTextImpl mText;
-        final Bundle mExtras;
+        ViewNodeText mText;
+        Bundle mExtras;
 
-        final ViewNode[] mChildren;
+        ViewNode[] mChildren;
 
-        ViewNode(AssistStructure assistStructure, View view) {
-            mId = view.getId();
-            if (mId > 0 && (mId&0xff000000) != 0 && (mId&0x00ff0000) != 0
-                    && (mId&0x0000ffff) != 0) {
-                String pkg, type, entry;
-                try {
-                    Resources res = view.getResources();
-                    entry = res.getResourceEntryName(mId);
-                    type = res.getResourceTypeName(mId);
-                    pkg = res.getResourcePackageName(mId);
-                } catch (Resources.NotFoundException e) {
-                    entry = type = pkg = null;
-                }
-                mIdPackage = pkg;
-                mIdType = type;
-                mIdEntry = entry;
-            } else {
-                mIdPackage = mIdType = mIdEntry = null;
-            }
-            mX = view.getLeft();
-            mY = view.getTop();
-            mScrollX = view.getScrollX();
-            mScrollY = view.getScrollY();
-            mWidth = view.getWidth();
-            mHeight = view.getHeight();
-            int flags = view.getVisibility();
-            if (!view.isEnabled()) {
-                flags |= FLAGS_DISABLED;
-            }
-            if (!view.isClickable()) {
-                flags |= FLAGS_CLICKABLE;
-            }
-            if (!view.isFocusable()) {
-                flags |= FLAGS_FOCUSABLE;
-            }
-            if (!view.isFocused()) {
-                flags |= FLAGS_FOCUSED;
-            }
-            if (!view.isAccessibilityFocused()) {
-                flags |= FLAGS_ACCESSIBILITY_FOCUSED;
-            }
-            if (!view.isSelected()) {
-                flags |= FLAGS_SELECTED;
-            }
-            if (!view.isActivated()) {
-                flags |= FLAGS_ACTIVATED;
-            }
-            if (!view.isLongClickable()) {
-                flags |= FLAGS_LONG_CLICKABLE;
-            }
-            if (view instanceof Checkable) {
-                flags |= FLAGS_CHECKABLE;
-                if (((Checkable)view).isChecked()) {
-                    flags |= FLAGS_CHECKED;
-                }
-            }
-            mFlags = flags;
-            mClassName = view.getAccessibilityClassName().toString();
-            mContentDescription = view.getContentDescription();
-            final ViewAssistStructureImpl viewData = assistStructure.mTmpViewAssistStructureImpl;
-            final Bundle extras = assistStructure.mTmpExtras;
-            view.onProvideAssistStructure(viewData, extras);
-            if (viewData.mText != null || viewData.mHint != null) {
-                mText = new ViewNodeTextImpl(viewData);
-                assistStructure.mTmpViewAssistStructureImpl = new ViewAssistStructureImpl();
-            } else {
-                mText = null;
-            }
-            if (!extras.isEmpty()) {
-                mExtras = extras;
-                assistStructure.mTmpExtras = new Bundle();
-            } else {
-                mExtras = null;
-            }
-            if (view instanceof ViewGroup) {
-                ViewGroup vg = (ViewGroup)view;
-                final int NCHILDREN = vg.getChildCount();
-                if (NCHILDREN > 0) {
-                    mChildren = new ViewNode[NCHILDREN];
-                    for (int i=0; i<NCHILDREN; i++) {
-                        mChildren[i] = new ViewNode(assistStructure, vg.getChildAt(i));
-                    }
-                } else {
-                    mChildren = null;
-                }
-            } else {
-                mChildren = null;
-            }
+        ViewNode() {
         }
 
         ViewNode(Parcel in, PooledStringReader preader) {
@@ -406,7 +260,7 @@
             mClassName = preader.readString();
             mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             if (in.readInt() != 0) {
-                mText = new ViewNodeTextImpl(in);
+                mText = new ViewNodeText(in);
             } else {
                 mText = null;
             }
@@ -595,7 +449,250 @@
         }
     }
 
+    static class ViewNodeBuilder extends ViewAssistStructure {
+        final AssistStructure mAssist;
+        final ViewNode mNode;
+        final boolean mAsync;
+
+        ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
+            mAssist = assist;
+            mNode = node;
+            mAsync = async;
+        }
+
+        @Override
+        public void setId(int id, String packageName, String typeName, String entryName) {
+            mNode.mId = id;
+            mNode.mIdPackage = packageName;
+            mNode.mIdType = typeName;
+            mNode.mIdEntry = entryName;
+        }
+
+        @Override
+        public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
+            mNode.mX = left;
+            mNode.mY = top;
+            mNode.mScrollX = scrollX;
+            mNode.mScrollY = scrollY;
+            mNode.mWidth = width;
+            mNode.mHeight = height;
+        }
+
+        @Override
+        public void setVisibility(int visibility) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
+        }
+
+        @Override
+        public void setEnabled(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
+                    | (state ? 0 : ViewNode.FLAGS_DISABLED);
+        }
+
+        @Override
+        public void setClickable(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
+                    | (state ? ViewNode.FLAGS_CLICKABLE : 0);
+        }
+
+        @Override
+        public void setLongClickable(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
+                    | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
+        }
+
+        @Override
+        public void setFocusable(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
+                    | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
+        }
+
+        @Override
+        public void setFocused(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
+                    | (state ? ViewNode.FLAGS_FOCUSED : 0);
+        }
+
+        @Override
+        public void setAccessibilityFocused(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
+                    | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
+        }
+
+        @Override
+        public void setCheckable(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
+                    | (state ? ViewNode.FLAGS_CHECKABLE : 0);
+        }
+
+        @Override
+        public void setChecked(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
+                    | (state ? ViewNode.FLAGS_CHECKED : 0);
+        }
+
+        @Override
+        public void setSelected(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
+                    | (state ? ViewNode.FLAGS_SELECTED : 0);
+        }
+
+        @Override
+        public void setActivated(boolean state) {
+            mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
+                    | (state ? ViewNode.FLAGS_ACTIVATED : 0);
+        }
+
+        @Override
+        public void setClassName(String className) {
+            mNode.mClassName = className;
+        }
+
+        @Override
+        public void setContentDescription(CharSequence contentDescription) {
+            mNode.mContentDescription = contentDescription;
+        }
+
+        private final ViewNodeText getNodeText() {
+            if (mNode.mText != null) {
+                return mNode.mText;
+            }
+            mNode.mText = new ViewNodeText();
+            return mNode.mText;
+        }
+
+        @Override
+        public void setText(CharSequence text) {
+            ViewNodeText t = getNodeText();
+            t.mText = text;
+            t.mTextSelectionStart = t.mTextSelectionEnd = -1;
+        }
+
+        @Override
+        public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+            ViewNodeText t = getNodeText();
+            t.mText = text;
+            t.mTextSelectionStart = selectionStart;
+            t.mTextSelectionEnd = selectionEnd;
+        }
+
+        @Override
+        public void setTextPaint(TextPaint paint) {
+            ViewNodeText t = getNodeText();
+            t.mTextColor = paint.getColor();
+            t.mTextBackgroundColor = paint.bgColor;
+            t.mTextSize = paint.getTextSize();
+            t.mTextStyle = 0;
+            Typeface tf = paint.getTypeface();
+            if (tf != null) {
+                if (tf.isBold()) {
+                    t.mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
+                }
+                if (tf.isItalic()) {
+                    t.mTextStyle |= ViewNode.TEXT_STYLE_ITALIC;
+                }
+            }
+            int pflags = paint.getFlags();
+            if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
+                t.mTextStyle |= ViewNode.TEXT_STYLE_BOLD;
+            }
+            if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) {
+                t.mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE;
+            }
+            if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
+                t.mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU;
+            }
+        }
+
+        @Override
+        public void setHint(CharSequence hint) {
+            getNodeText().mHint = hint != null ? hint.toString() : null;
+        }
+
+        @Override
+        public CharSequence getText() {
+            return mNode.mText != null ? mNode.mText.mText : null;
+        }
+
+        @Override
+        public int getTextSelectionStart() {
+            return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
+        }
+
+        @Override
+        public int getTextSelectionEnd() {
+            return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
+        }
+
+        @Override
+        public CharSequence getHint() {
+            return mNode.mText != null ? mNode.mText.mHint : null;
+        }
+
+        @Override
+        public Bundle editExtras() {
+            if (mNode.mExtras != null) {
+                return mNode.mExtras;
+            }
+            mNode.mExtras = new Bundle();
+            return mNode.mExtras;
+        }
+
+        @Override
+        public void clearExtras() {
+            mNode.mExtras = null;
+        }
+
+        @Override
+        public void setChildCount(int num) {
+            mNode.mChildren = new ViewNode[num];
+        }
+
+        @Override
+        public int getChildCount() {
+            return mNode.mChildren != null ? mNode.mChildren.length : 0;
+        }
+
+        @Override
+        public ViewAssistStructure newChild(int index) {
+            ViewNode node = new ViewNode();
+            mNode.mChildren[index] = node;
+            return new ViewNodeBuilder(mAssist, node, false);
+        }
+
+        @Override
+        public ViewAssistStructure asyncNewChild(int index) {
+            synchronized (mAssist) {
+                ViewNode node = new ViewNode();
+                mNode.mChildren[index] = node;
+                ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
+                mAssist.mPendingAsyncChildren.add(builder);
+                return builder;
+            }
+        }
+
+        @Override
+        public void asyncCommit() {
+            synchronized (mAssist) {
+                if (!mAsync) {
+                    throw new IllegalStateException("Child " + this
+                            + " was not created with ViewAssistStructure.asyncNewChild");
+                }
+                if (!mAssist.mPendingAsyncChildren.remove(this)) {
+                    throw new IllegalStateException("Child " + this + " already committed");
+                }
+                mAssist.notifyAll();
+            }
+        }
+
+        @Override
+        public Rect getTempRect() {
+            return mAssist.mTmpRect;
+        }
+    }
+
     AssistStructure(Activity activity) {
+        mHaveData = true;
         mActivityComponent = activity.getComponentName();
         ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
                 activity.getActivityToken());
@@ -606,13 +703,7 @@
     }
 
     AssistStructure(Parcel in) {
-        PooledStringReader preader = new PooledStringReader(in);
-        mActivityComponent = ComponentName.readFromParcel(in);
-        final int N = in.readInt();
-        for (int i=0; i<N; i++) {
-            mWindowNodes.add(new WindowNode(in, preader));
-        }
-        //dump();
+        mReceiveChannel = in.readStrongBinder();
     }
 
     /** @hide */
@@ -689,6 +780,7 @@
     }
 
     public ComponentName getActivityComponent() {
+        ensureData();
         return mActivityComponent;
     }
 
@@ -696,6 +788,7 @@
      * Return the number of window contents that have been collected in this assist data.
      */
     public int getWindowNodeCount() {
+        ensureData();
         return mWindowNodes.size();
     }
 
@@ -704,6 +797,7 @@
      * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
      */
     public WindowNode getWindowNodeAt(int index) {
+        ensureData();
         return mWindowNodes.get(index);
     }
 
@@ -711,11 +805,47 @@
         return 0;
     }
 
-    public void writeToParcel(Parcel out, int flags) {
+    /** @hide */
+    public void ensureData() {
+        if (mHaveData) {
+            return;
+        }
+        mHaveData = true;
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(DESCRIPTOR);
+        try {
+            mReceiveChannel.transact(TRANSACTION_XFER, data, reply, 0);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failure reading AssistStructure data", e);
+            return;
+        }
+        readContentFromParcel(reply);
+        data.recycle();
+        reply.recycle();
+    }
+
+    void writeContentToParcel(Parcel out, int flags) {
+        // First make sure all content has been created.
+        boolean skipStructure = false;
+        synchronized (this) {
+            long endTime = SystemClock.uptimeMillis() + 5000;
+            long now;
+            while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
+                try {
+                    wait(endTime-now);
+                } catch (InterruptedException e) {
+                }
+            }
+            if (mPendingAsyncChildren.size() > 0) {
+                // We waited too long, assume none of the assist structure is valid.
+                skipStructure = true;
+            }
+        }
         int start = out.dataPosition();
         PooledStringWriter pwriter = new PooledStringWriter(out);
         ComponentName.writeToParcel(mActivityComponent, out);
-        final int N = mWindowNodes.size();
+        final int N = skipStructure ? 0 : mWindowNodes.size();
         out.writeInt(N);
         for (int i=0; i<N; i++) {
             mWindowNodes.get(i).writeToParcel(out, pwriter);
@@ -724,6 +854,30 @@
         Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
     }
 
+    void readContentFromParcel(Parcel in) {
+        PooledStringReader preader = new PooledStringReader(in);
+        mActivityComponent = ComponentName.readFromParcel(in);
+        final int N = in.readInt();
+        for (int i=0; i<N; i++) {
+            mWindowNodes.add(new WindowNode(in, preader));
+        }
+        //dump();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        if (mHaveData) {
+            // This object holds its data.  We want to write a send channel that the
+            // other side can use to retrieve that data.
+            if (mSendChannel == null) {
+                mSendChannel = new SendChannel();
+            }
+            out.writeStrongBinder(mSendChannel);
+        } else {
+            // This object doesn't hold its data, so just propagate along its receive channel.
+            out.writeStrongBinder(mReceiveChannel);
+        }
+    }
+
     public static final Parcelable.Creator<AssistStructure> CREATOR
             = new Parcelable.Creator<AssistStructure>() {
         public AssistStructure createFromParcel(Parcel in) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 9defcbe5..786a52f 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -20,10 +20,11 @@
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
+import android.annotation.NonNull;
 import android.annotation.StringRes;
-import com.android.internal.app.WindowDecorActionBar;
 
 import android.annotation.Nullable;
+import android.annotation.StyleRes;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -56,6 +57,9 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 
+import com.android.internal.R;
+import com.android.internal.app.WindowDecorActionBar;
+
 import java.lang.ref.WeakReference;
 
 /**
@@ -130,52 +134,58 @@
     };
 
     /**
-     * Create a Dialog window that uses the default dialog frame style.
-     * 
-     * @param context The Context the Dialog is to run it.  In particular, it
-     *                uses the window manager and theme in this context to
-     *                present its UI.
+     * Creates a dialog window that uses the default dialog theme.
+     * <p>
+     * The supplied {@code context} is used to obtain the window manager and
+     * base theme used to present the dialog.
+     *
+     * @param context the context in which the dialog should run
+     * @see android.R.styleable#Theme_dialogTheme
      */
-    public Dialog(Context context) {
+    public Dialog(@NonNull Context context) {
         this(context, 0, true);
     }
 
     /**
-     * Create a Dialog window that uses a custom dialog style.
+     * Creates a dialog window that uses a custom dialog style.
+     * <p>
+     * The supplied {@code context} is used to obtain the window manager and
+     * base theme used to present the dialog.
+     * <p>
+     * The supplied {@code theme} is applied on top of the context's theme. See
+     * <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">
+     * Style and Theme Resources</a> for more information about defining and
+     * using styles.
      *
-     * @param context The Context in which the Dialog should run. In particular, it
-     *                uses the window manager and theme from this context to
-     *                present its UI.
-     * @param theme A style resource describing the theme to use for the
-     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
-     * and Theme Resources</a> for more information about defining and using
-     * styles.  This theme is applied on top of the current theme in
-     * <var>context</var>.  If 0, the default dialog theme will be used.
+     * @param context the context in which the dialog should run
+     * @param themeResId a style resource describing the theme to use for the
+     *              window, or {@code 0} to use the default dialog theme
      */
-    public Dialog(Context context, int theme) {
-        this(context, theme, true);
+    public Dialog(@NonNull Context context, @StyleRes int themeResId) {
+        this(context, themeResId, true);
     }
 
-    Dialog(Context context, int theme, boolean createContextThemeWrapper) {
+    Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
         if (createContextThemeWrapper) {
-            if (theme == 0) {
-                TypedValue outValue = new TypedValue();
-                context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
-                        outValue, true);
-                theme = outValue.resourceId;
+            if (themeResId == 0) {
+                final TypedValue outValue = new TypedValue();
+                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
+                themeResId = outValue.resourceId;
             }
-            mContext = new ContextThemeWrapper(context, theme);
+            mContext = new ContextThemeWrapper(context, themeResId);
         } else {
             mContext = context;
         }
 
-        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
-        Window w = new PhoneWindow(mContext);
+        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+
+        final Window w = new PhoneWindow(mContext);
         mWindow = w;
         w.setCallback(this);
         w.setOnWindowDismissedCallback(this);
         w.setWindowManager(mWindowManager, null, null);
         w.setGravity(Gravity.CENTER);
+
         mListenersHandler = new ListenersHandler(this);
     }
 
@@ -184,14 +194,13 @@
      * @hide
      */
     @Deprecated
-    protected Dialog(Context context, boolean cancelable,
-            Message cancelCallback) {
+    protected Dialog(@NonNull Context context, boolean cancelable, Message cancelCallback) {
         this(context);
         mCancelable = cancelable;
         mCancelMessage = cancelCallback;
     }
 
-    protected Dialog(Context context, boolean cancelable,
+    protected Dialog(@NonNull Context context, boolean cancelable,
             OnCancelListener cancelListener) {
         this(context);
         mCancelable = cancelable;
@@ -203,6 +212,7 @@
      * 
      * @return Context The Context used by the Dialog.
      */
+    @NonNull
     public final Context getContext() {
         return mContext;
     }
diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java
index c053c83..e84a8da 100644
--- a/core/java/android/app/EnterTransitionCoordinator.java
+++ b/core/java/android/app/EnterTransitionCoordinator.java
@@ -18,6 +18,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.app.SharedElementCallback.OnSharedElementsReadyListener;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.ResultReceiver;
@@ -140,13 +141,13 @@
         } else {
             decor.getViewTreeObserver()
                     .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                @Override
-                public boolean onPreDraw() {
-                    decor.getViewTreeObserver().removeOnPreDrawListener(this);
-                    viewsReady(sharedElements);
-                    return true;
-                }
-            });
+                        @Override
+                        public boolean onPreDraw() {
+                            decor.getViewTreeObserver().removeOnPreDrawListener(this);
+                            viewsReady(sharedElements);
+                            return true;
+                        }
+                    });
         }
     }
 
@@ -383,23 +384,33 @@
         }
         final Bundle sharedElementState = mSharedElementsBundle;
         mSharedElementsBundle = null;
-        final View decorView = getDecor();
-        if (decorView != null) {
-            decorView.getViewTreeObserver()
-                    .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
-                        @Override
-                        public boolean onPreDraw() {
-                            decorView.getViewTreeObserver().removeOnPreDrawListener(this);
-                            startTransition(new Runnable() {
+        OnSharedElementsReadyListener listener = new OnSharedElementsReadyListener() {
+            @Override
+            public void onSharedElementsReady() {
+                final View decorView = getDecor();
+                if (decorView != null) {
+                    decorView.getViewTreeObserver()
+                            .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                                 @Override
-                                public void run() {
-                                    startSharedElementTransition(sharedElementState);
+                                public boolean onPreDraw() {
+                                    decorView.getViewTreeObserver().removeOnPreDrawListener(this);
+                                    startTransition(new Runnable() {
+                                        @Override
+                                        public void run() {
+                                            startSharedElementTransition(sharedElementState);
+                                        }
+                                    });
+                                    return false;
                                 }
                             });
-                            return false;
-                        }
-                    });
-            decorView.invalidate();
+                    decorView.invalidate();
+                }
+            }
+        };
+        if (mListener == null) {
+            listener.onSharedElementsReady();
+        } else {
+            mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements, listener);
         }
     }
 
diff --git a/core/java/android/app/ExitTransitionCoordinator.java b/core/java/android/app/ExitTransitionCoordinator.java
index dd3df47..169952ad 100644
--- a/core/java/android/app/ExitTransitionCoordinator.java
+++ b/core/java/android/app/ExitTransitionCoordinator.java
@@ -18,6 +18,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.app.SharedElementCallback.OnSharedElementsReadyListener;
 import android.content.Intent;
 import android.graphics.Color;
 import android.graphics.Matrix;
@@ -27,6 +28,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.os.ResultReceiver;
 import android.transition.Transition;
 import android.transition.TransitionManager;
 import android.view.View;
@@ -408,21 +410,41 @@
             if (!mSharedElementNotified) {
                 mSharedElementNotified = true;
                 delayCancel();
-                mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
-            }
-            if (!mExitNotified && mExitComplete) {
-                mExitNotified = true;
-                mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
-                mResultReceiver = null; // done talking
-                ViewGroup decorView = getDecor();
-                if (!mIsReturning && decorView != null) {
-                    decorView.suppressLayout(false);
+                if (mListener == null) {
+                    mResultReceiver.send(MSG_TAKE_SHARED_ELEMENTS, mSharedElementBundle);
+                    notifyExitComplete();
+                } else {
+                    final ResultReceiver resultReceiver = mResultReceiver;
+                    final Bundle sharedElementBundle = mSharedElementBundle;
+                    mListener.onSharedElementsArrived(mSharedElementNames, mSharedElements,
+                            new OnSharedElementsReadyListener() {
+                                @Override
+                                public void onSharedElementsReady() {
+                                    resultReceiver.send(MSG_TAKE_SHARED_ELEMENTS,
+                                            sharedElementBundle);
+                                    notifyExitComplete();
+                                }
+                            });
                 }
-                finishIfNecessary();
+            } else {
+                notifyExitComplete();
             }
         }
     }
 
+    private void notifyExitComplete() {
+        if (!mExitNotified && mExitComplete) {
+            mExitNotified = true;
+            mResultReceiver.send(MSG_EXIT_TRANSITION_COMPLETE, null);
+            mResultReceiver = null; // done talking
+            ViewGroup decorView = getDecor();
+            if (!mIsReturning && decorView != null) {
+                decorView.suppressLayout(false);
+            }
+            finishIfNecessary();
+        }
+    }
+
     private void finishIfNecessary() {
         if (mIsReturning && mExitNotified && mActivity != null && (mSharedElements.isEmpty() ||
                 mSharedElementsHidden)) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index d794aa3..4a1d6ff 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -482,11 +482,13 @@
     public void systemBackupRestored() throws RemoteException;
     public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
 
-    public void setDumpHeapDebugLimit(String processName, long maxMemSize) throws RemoteException;
+    public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
+            String reportPackage) throws RemoteException;
     public void dumpHeapFinished(String path) throws RemoteException;
 
     public void setVoiceKeepAwake(IVoiceInteractionSession session, boolean keepAwake)
             throws RemoteException;
+    public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;
 
     /*
      * Private non-Binder interfaces
@@ -822,4 +824,5 @@
     int SET_DUMP_HEAP_DEBUG_LIMIT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+287;
     int DUMP_HEAP_FINISHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+288;
     int SET_VOICE_KEEP_AWAKE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+289;
+    int UPDATE_LOCK_TASK_PACKAGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+290;
 }
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 194082e..d5719f5 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -28,7 +28,7 @@
 interface IAlarmManager {
 	/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
     void set(int type, long triggerAtTime, long windowLength,
-            long interval, in PendingIntent operation, in WorkSource workSource,
+            long interval, int flags, in PendingIntent operation, in WorkSource workSource,
             in AlarmManager.AlarmClockInfo alarmClock);
     boolean setTime(long millis);
     void setTimeZone(String zone);
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 33262b3..e2230da 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -76,12 +76,10 @@
     boolean matchesCallFilter(in Bundle extras);
     boolean isSystemConditionProviderEnabled(String path);
 
+    int getZenMode();
     ZenModeConfig getZenModeConfig();
-    boolean setZenModeConfig(in ZenModeConfig config);
-    oneway void setZenMode(int mode);
+    boolean setZenModeConfig(in ZenModeConfig config, String reason);
+    oneway void setZenMode(int mode, in Uri conditionId, String reason);
     oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
     oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
-    oneway void setZenModeCondition(in Condition condition);
-    oneway void setAutomaticZenModeConditions(in Uri[] conditionIds);
-    Condition[] getAutomaticZenModeConditions();
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b31ce04..e7f8f6d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -646,6 +646,11 @@
     public static final String CATEGORY_STATUS = "status";
 
     /**
+     * Notification category: user-scheduled reminder.
+     */
+    public static final String CATEGORY_REMINDER = "reminder";
+
+    /**
      * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
      * that best describes this Notification.  May be used by the system for ranking and filtering.
      */
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 479327d..fa61e18 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -20,6 +20,7 @@
 import android.app.Notification.Builder;
 import android.content.ComponentName;
 import android.content.Context;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -27,7 +28,7 @@
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.UserHandle;
-import android.service.notification.Condition;
+import android.provider.Settings.Global;
 import android.service.notification.IConditionListener;
 import android.service.notification.ZenModeConfig;
 import android.util.Log;
@@ -282,10 +283,10 @@
     /**
      * @hide
      */
-    public void setZenMode(int mode) {
+    public void setZenMode(int mode, Uri conditionId, String reason) {
         INotificationManager service = getService();
         try {
-            service.setZenMode(mode);
+            service.setZenMode(mode, conditionId, reason);
         } catch (RemoteException e) {
         }
     }
@@ -293,6 +294,18 @@
     /**
      * @hide
      */
+    public boolean setZenModeConfig(ZenModeConfig config, String reason) {
+        INotificationManager service = getService();
+        try {
+            return service.setZenModeConfig(config, reason);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
+     * @hide
+     */
     public void requestZenModeConditions(IConditionListener listener, int relevance) {
         INotificationManager service = getService();
         try {
@@ -304,24 +317,22 @@
     /**
      * @hide
      */
-    public void setZenModeCondition(Condition exitCondition) {
+    public int getZenMode() {
         INotificationManager service = getService();
         try {
-            service.setZenModeCondition(exitCondition);
+            return service.getZenMode();
         } catch (RemoteException e) {
         }
+        return Global.ZEN_MODE_OFF;
     }
 
     /**
      * @hide
      */
-    public Condition getZenModeCondition() {
+    public ZenModeConfig getZenModeConfig() {
         INotificationManager service = getService();
         try {
-            final ZenModeConfig config = service.getZenModeConfig();
-            if (config != null) {
-                return config.exitCondition;
-            }
+            return service.getZenModeConfig();
         } catch (RemoteException e) {
         }
         return null;
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index cf14202..2cfc1fa4 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -151,6 +151,14 @@
     public static final int FLAG_UPDATE_CURRENT = 1<<27;
 
     /**
+     * Flag indicating that the created PendingIntent should be immutable.
+     * This means that the additional intent argument passed to the send
+     * methods to fill in unpopulated properties of this intent will be
+     * ignored.
+     */
+    public static final int FLAG_IMMUTABLE = 1<<26;
+
+    /**
      * Exception thrown when trying to send through a PendingIntent that
      * has been canceled or is otherwise no longer able to execute the request.
      */
@@ -618,7 +626,8 @@
      * @param code Result code to supply back to the PendingIntent's target.
      * @param intent Additional Intent data.  See {@link Intent#fillIn
      * Intent.fillIn()} for information on how this is applied to the
-     * original Intent.
+     * original Intent. If flag {@link #FLAG_IMMUTABLE} was set when this
+     * pending intent was created, this argument will be ignored.
      *
      * @see #send(Context, int, Intent, android.app.PendingIntent.OnFinished, Handler)
      *
@@ -667,6 +676,8 @@
      * @param intent Additional Intent data.  See {@link Intent#fillIn
      * Intent.fillIn()} for information on how this is applied to the
      * original Intent.  Use null to not modify the original Intent.
+     * If flag {@link #FLAG_IMMUTABLE} was set when this pending intent was
+     * created, this argument will be ignored.
      * @param onFinished The object to call back on when the send has
      * completed, or null for no callback.
      * @param handler Handler identifying the thread on which the callback
@@ -703,6 +714,8 @@
      * @param intent Additional Intent data.  See {@link Intent#fillIn
      * Intent.fillIn()} for information on how this is applied to the
      * original Intent.  Use null to not modify the original Intent.
+     * If flag {@link #FLAG_IMMUTABLE} was set when this pending intent was
+     * created, this argument will be ignored.
      * @param onFinished The object to call back on when the send has
      * completed, or null for no callback.
      * @param handler Handler identifying the thread on which the callback
diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java
index 6ac2401..e58b7fb 100644
--- a/core/java/android/app/SharedElementCallback.java
+++ b/core/java/android/app/SharedElementCallback.java
@@ -221,4 +221,42 @@
         }
         return view;
     }
+
+    /**
+     * Called during an Activity Transition when the shared elements have arrived at the
+     * final location and are ready to be transferred. This method is called for both the
+     * source and destination Activities.
+     * <p>
+     * When the shared elements are ready to be transferred,
+     * {@link OnSharedElementsReadyListener#onSharedElementsReady()}
+     * must be called to trigger the transfer.
+     * <p>
+     * The default behavior is to trigger the transfer immediately.
+     *
+     * @param sharedElementNames The names of the shared elements that are being transferred..
+     * @param sharedElements The shared elements that are part of the View hierarchy.
+     * @param listener The listener to call when the shared elements are ready to be hidden
+     *                 in the source Activity or shown in the destination Activity.
+     */
+    public void onSharedElementsArrived(List<String> sharedElementNames,
+            List<View> sharedElements, OnSharedElementsReadyListener listener) {
+        listener.onSharedElementsReady();
+    }
+
+    /**
+     * Listener to be called after {@link
+     * SharedElementCallback#onSharedElementsArrived(List, List, OnSharedElementsReadyListener)}
+     * when the shared elements are ready to be hidden in the source Activity and shown in the
+     * destination Activity.
+     */
+    public interface OnSharedElementsReadyListener {
+
+        /**
+         * Call this method during or after the OnSharedElementsReadyListener has been received
+         * in {@link SharedElementCallback#onSharedElementsArrived(List, List,
+         * OnSharedElementsReadyListener)} to indicate that the shared elements are ready to be
+         * hidden in the source and shown in the destination Activity.
+         */
+        void onSharedElementsReady();
+    }
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index a0f40f6..b3aa6be 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -99,8 +99,8 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
-import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telecom.TelecomManager;
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index b0dd70f..a8494fb 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -690,7 +690,7 @@
      * potentially undesirable actions such as calling 911 or posting on public forums etc.
      *
      * @param enable whether to run in a "monkey" mode or not. Default is not.
-     * @see {@link android.app.ActivityManager#isUserAMonkey()}
+     * @see ActivityManager#isUserAMonkey()
      */
     public void setRunAsMonkey(boolean enable) {
         synchronized (mLock) {
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index da7bb05..022a62c 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -103,9 +103,9 @@
                     request = pullRequest((IVoiceInteractorRequest)args.arg1, true);
                     if (DEBUG) Log.d(TAG, "onCompleteVoice: req="
                             + ((IVoiceInteractorRequest)args.arg1).asBinder() + "/" + request
-                            + " result=" + args.arg1);
+                            + " result=" + args.arg2);
                     if (request != null) {
-                        ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg1);
+                        ((CompleteVoiceRequest)request).onCompleteResult((Bundle) args.arg2);
                         request.clear();
                     }
                     break;
@@ -297,6 +297,7 @@
          */
         public static final class Option implements Parcelable {
             final CharSequence mLabel;
+            final int mIndex;
             ArrayList<CharSequence> mSynonyms;
             Bundle mExtras;
 
@@ -308,6 +309,21 @@
              */
             public Option(CharSequence label) {
                 mLabel = label;
+                mIndex = -1;
+            }
+
+            /**
+             * Creates an option that a user can select with their voice by matching the label
+             * or one of several synonyms.
+             * @param label The label that will both be matched against what the user speaks
+             * and displayed visually.
+             * @param index The location of this option within the overall set of options.
+             * Can be used to help identify the option when it is returned from the
+             * voice interactor.
+             */
+            public Option(CharSequence label, int index) {
+                mLabel = label;
+                mIndex = index;
             }
 
             /**
@@ -328,6 +344,14 @@
                 return mLabel;
             }
 
+            /**
+             * Return the index that was supplied in the constructor.
+             * If the option was constructed without an index, -1 is returned.
+             */
+            public int getIndex() {
+                return mIndex;
+            }
+
             public int countSynonyms() {
                 return mSynonyms != null ? mSynonyms.size() : 0;
             }
@@ -356,6 +380,7 @@
 
             Option(Parcel in) {
                 mLabel = in.readCharSequence();
+                mIndex = in.readInt();
                 mSynonyms = in.readCharSequenceList();
                 mExtras = in.readBundle();
             }
@@ -368,6 +393,7 @@
             @Override
             public void writeToParcel(Parcel dest, int flags) {
                 dest.writeCharSequence(mLabel);
+                dest.writeInt(mIndex);
                 dest.writeCharSequenceList(mSynonyms);
                 dest.writeBundle(mExtras);
             }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index cbb0f51..68f4707 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -502,6 +502,20 @@
      */
     public static final String EXTRA_PROVISIONING_BT_USE_PROXY
             = "android.app.extra.PROVISIONING_BT_USE_PROXY";
+
+    /**
+     * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
+     * holds data needed by the system to wipe factory reset protection. The data needed to wipe
+     * the device depend on the installed factory reset protection implementation. For example,
+     * if an account is needed to unlock a device, this extra may contain data used to
+     * authenticate that account.
+     *
+     * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
+     * provisioning via an NFC bump.
+     */
+    public static final String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS
+            = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS";
+
     /**
      * This MIME type is used for starting the Device Owner provisioning that does not require
      * provisioning features introduced in Android API level
@@ -2639,8 +2653,8 @@
      *        called by the device owner.
      * @param initializer Which {@link DeviceAdminReceiver} to make device initializer.
      * @param initializerName The user-visible name of the device initializer.
-     * @return whether the package was successfully registered as the device initializer.
-     * @throws IllegalArgumentException if the package name is null or invalid
+     * @return whether the component was successfully registered as the device initializer.
+     * @throws IllegalArgumentException if the componentname is null or invalid
      * @throws IllegalStateException if the caller is not device owner or the device has
      *         already been provisioned or a device initializer already exists.
      */
@@ -2710,6 +2724,25 @@
     }
 
     /**
+     * @hide
+     * Gets the device initializer component of the system.
+     *
+     * @return the component name of the device initializer.
+     */
+    @SystemApi
+    public ComponentName getDeviceInitializerComponent() {
+        if (mService != null) {
+            try {
+                return mService.getDeviceInitializerComponent();
+            } catch (RemoteException re) {
+                Log.w(TAG, "Failed to get device initializer");
+            }
+        }
+        return null;
+    }
+
+
+    /**
      * Sets the enabled state of the user. A user should be enabled only once it is ready to
      * be used.
      *
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 73b0684..c68311e 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -210,6 +210,7 @@
     void clearDeviceInitializer(in ComponentName who);
     boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName);
     String getDeviceInitializer();
+    ComponentName getDeviceInitializerComponent();
 
     void setUserIcon(in ComponentName admin, in Bitmap icon);
 }
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 9151a16..8b79305 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -339,4 +339,30 @@
             }
         }
     }
+
+    /**
+     * Ask the framework which dataset, if any, the given package's data would be
+     * restored from if we were to install it right now.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @param packageName The name of the package whose most-suitable dataset we
+     *     wish to look up
+     * @return The dataset token from which a restore should be attempted, or zero if
+     *     no suitable data is available.
+     *
+     * @hide
+     */
+    @SystemApi
+    public long getAvailableRestoreToken(String packageName) {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                return sService.getAvailableRestoreToken(packageName);
+            } catch (RemoteException e) {
+                Log.e(TAG, "getAvailableRestoreToken() couldn't connect");
+            }
+        }
+        return 0;
+    }
 }
diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java
index ca6dc69..1131ff9 100644
--- a/core/java/android/app/backup/BackupTransport.java
+++ b/core/java/android/app/backup/BackupTransport.java
@@ -464,7 +464,7 @@
      * transport level).
      *
      * <p>After this method returns zero, the system will then call
-     * {@link #getNextFullRestorePackage()} to begin the restore process for the next
+     * {@link #nextRestorePackage()} to begin the restore process for the next
      * application, and the sequence begins again.
      *
      * <p>The transport should always close this socket when returning from this method.
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index 8f36dc4..87e4ef1 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -313,4 +313,17 @@
      *     is being queried.
      */
     boolean isBackupServiceActive(int whichUser);
+
+    /**
+     * Ask the framework which dataset, if any, the given package's data would be
+     * restored from if we were to install it right now.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     *
+     * @param packageName The name of the package whose most-suitable dataset we
+     *     wish to look up
+     * @return The dataset token from which a restore should be attempted, or zero if
+     *     no suitable data is available.
+     */
+    long getAvailableRestoreToken(String packageName);
 }
diff --git a/core/java/android/app/backup/RecentsBackupHelper.java b/core/java/android/app/backup/RecentsBackupHelper.java
index fd69d20..1a64da6 100644
--- a/core/java/android/app/backup/RecentsBackupHelper.java
+++ b/core/java/android/app/backup/RecentsBackupHelper.java
@@ -1,3 +1,19 @@
+/*
+ * 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.backup;
 
 import android.content.Context;
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 0122069..8b3fc2e 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -57,4 +57,41 @@
      * Prepares the UsageStatsService for shutdown.
      */
     public abstract void prepareShutdown();
+
+    /**
+     * Returns true if the app has not been used for a certain amount of time. How much time?
+     * Could be hours, could be days, who knows?
+     *
+     * @param packageName
+     * @param userId
+     * @return
+     */
+    public abstract boolean isAppIdle(String packageName, int userId);
+
+    /**
+     * Returns the most recent time that the specified package was active for the given user.
+     * @param packageName The package to search.
+     * @param userId The user id of the user of interest.
+     * @return The timestamp of when the package was last used, or -1 if it hasn't been used.
+     */
+    public abstract long getLastPackageAccessTime(String packageName, int userId);
+
+    /**
+     * Sets up a listener for changes to packages being accessed.
+     * @param listener A listener within the system process.
+     */
+    public abstract void addAppIdleStateChangeListener(
+            AppIdleStateChangeListener listener);
+
+    /**
+     * Removes a listener that was previously added for package usage state changes.
+     * @param listener The listener within the system process to remove.
+     */
+    public abstract void removeAppIdleStateChangeListener(
+            AppIdleStateChangeListener listener);
+
+    public interface AppIdleStateChangeListener {
+        void onAppIdleStateChanged(String packageName, int userId, boolean idle);
+    }
+
 }
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index be26eac..edb768d0 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.bluetooth.le.BluetoothLeAdvertiser;
 import android.bluetooth.le.BluetoothLeScanner;
 import android.bluetooth.le.ScanCallback;
@@ -206,6 +207,23 @@
             "android.bluetooth.adapter.action.REQUEST_ENABLE";
 
     /**
+     * Activity Action: Show a system activity that allows user to enable BLE scans even when
+     * Bluetooth is turned off.<p>
+     *
+     * Notification of result of this activity is posted using
+     * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
+     * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
+     * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
+     * error occurred.
+     *
+     * @hide
+     */
+    @SystemApi
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
+            "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
+
+    /**
      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
      * has changed.
      * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
@@ -916,6 +934,22 @@
     }
 
     /**
+     * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
+     *
+     * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
+     * fetch scan results even when Bluetooth is turned off.<p>
+     *
+     * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean isBleScanAlwaysAvailable() {
+        // TODO: implement after Settings UI change.
+        return false;
+    }
+
+    /**
      * Returns whether peripheral mode is supported.
      *
      * @hide
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 93ea299..5dbfa6a 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -36,7 +36,7 @@
 
 /**
  * This class provides methods to perform scan related operations for Bluetooth LE devices. An
- * application can scan for a particular type of Bluetotoh LE devices using {@link ScanFilter}. It
+ * application can scan for a particular type of Bluetooth LE devices using {@link ScanFilter}. It
  * can also request different types of callbacks for delivering the result.
  * <p>
  * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index e9d4e59..9450dce 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -16,6 +16,7 @@
 
 package android.content;
 
+import android.annotation.AttrRes;
 import android.annotation.CheckResult;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -474,8 +475,7 @@
      *
      * @see android.content.res.Resources.Theme#obtainStyledAttributes(int[])
      */
-    public final TypedArray obtainStyledAttributes(
-            int[] attrs) {
+    public final TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
         return getTheme().obtainStyledAttributes(attrs);
     }
 
@@ -487,7 +487,7 @@
      * @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[])
      */
     public final TypedArray obtainStyledAttributes(
-            @StyleableRes int resid, int[] attrs) throws Resources.NotFoundException {
+            @StyleRes int resid, @StyleableRes int[] attrs) throws Resources.NotFoundException {
         return getTheme().obtainStyledAttributes(resid, attrs);
     }
 
@@ -499,7 +499,7 @@
      * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
      */
     public final TypedArray obtainStyledAttributes(
-            AttributeSet set, int[] attrs) {
+            AttributeSet set, @StyleableRes int[] attrs) {
         return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
     }
 
@@ -511,7 +511,8 @@
      * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)
      */
     public final TypedArray obtainStyledAttributes(
-            AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
+            AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr,
+            @StyleRes int defStyleRes) {
         return getTheme().obtainStyledAttributes(
             set, attrs, defStyleAttr, defStyleRes);
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7a99a79..eea47b7 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1041,6 +1041,18 @@
      */
     public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
     /**
+     * Activity action: Activate the current SIM card.  If SIM cards do not require activation,
+     * sending this intent is a no-op.
+     * <p>Input: No data should be specified.  get*Extra may have an optional
+     * {@link #EXTRA_SIM_ACTIVATION_RESPONSE} field containing a PendingIntent through which to
+     * send the activation result.
+     * <p>Output: nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SIM_ACTIVATION_REQUEST =
+            "android.intent.action.SIM_ACTIVATION_REQUEST";
+    /**
      * Activity Action: Send a message to someone specified by the data.
      * <p>Input: {@link #getData} is URI describing the target.
      * <p>Output: nothing.
@@ -2896,6 +2908,24 @@
     /** {@hide} */
     public static final String EXTRA_SETTING_NEW_VALUE = "new_value";
 
+    /**
+     * Activity Action: Process a piece of text.
+     * <p>Input: {@link #EXTRA_PROCESS_TEXT} contains the text to be processed.
+     * {@link #EXTRA_PROCESS_TEXT_READONLY} states if the resulting text will be read-only.</p>
+     * <p>Output: {@link #EXTRA_PROCESS_TEXT} contains the processed text.</p>
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
+    /**
+     * The name of the extra used to define the text to be processed.
+     */
+    public static final String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
+    /**
+     * The name of the extra used to define if the processed text will be used as read-only.
+     */
+    public static final String EXTRA_PROCESS_TEXT_READONLY =
+            "android.intent.extra.PROCESS_TEXT_READONLY";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
@@ -3620,6 +3650,15 @@
     /** {@hide} */
     public static final String EXTRA_REASON = "android.intent.extra.REASON";
 
+    /**
+     * Optional {@link android.app.PendingIntent} extra used to deliver the result of the SIM
+     * activation request.
+     * TODO: Add information about the structure and response data used with the pending intent.
+     * @hide
+     */
+    public static final String EXTRA_SIM_ACTIVATION_RESPONSE =
+            "android.intent.extra.SIM_ACTIVATION_RESPONSE";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Intent flags (see mFlags variable).
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 590d791..33c0b87 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -517,6 +517,42 @@
     }
 
     /**
+     * Return if this filter handle all HTTP or HTTPS data URI or not.
+     *
+     * @return True if the filter handle all HTTP or HTTPS data URI. False otherwise.
+     *
+     * This will check if:
+     *
+     * - either the Intent category is {@link android.content.Intent#CATEGORY_APP_BROWSER}
+     * - either the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+     * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
+     * data scheme is "http" or "https" and that there is no specific host defined.
+     *
+     * @hide
+     */
+    public final boolean handleAllWebDataURI() {
+        return hasCategory(Intent.CATEGORY_APP_BROWSER) ||
+                (hasWebDataURI() && countDataAuthorities() == 0);
+    }
+
+    /**
+     * Return if this filter has any HTTP or HTTPS data URI or not.
+     *
+     * @return True if the filter has any HTTP or HTTPS data URI. False otherwise.
+     *
+     * This will check if if the Intent action is {@link android.content.Intent#ACTION_VIEW} and
+     * the Intent category is {@link android.content.Intent#CATEGORY_BROWSABLE} and the Intent
+     * data scheme is "http" or "https".
+     *
+     * @hide
+     */
+    public final boolean hasWebDataURI() {
+        return hasAction(Intent.ACTION_VIEW) &&
+                hasCategory(Intent.CATEGORY_BROWSABLE) &&
+                (hasDataScheme(SCHEME_HTTP) || hasDataScheme(SCHEME_HTTPS));
+    }
+
+    /**
      * Return if this filter needs to be automatically verified again its data URIs or not.
      *
      * @return True if the filter needs to be automatically verified. False otherwise.
@@ -530,10 +566,7 @@
      * @hide
      */
     public final boolean needsVerification() {
-        return hasAction(Intent.ACTION_VIEW) &&
-                hasCategory(Intent.CATEGORY_BROWSABLE) &&
-                (hasDataScheme(SCHEME_HTTP) || hasDataScheme(SCHEME_HTTPS)) &&
-                getAutoVerify();
+        return hasWebDataURI() && getAutoVerify();
     }
 
     /**
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index 6d79626..342ee38 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -20,6 +20,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Arrays;
+import java.util.Objects;
+
 /**
  * Applications can expose restrictions for a restricted user on a
  * multiuser device. The administrator can configure these restrictions that will then be
@@ -33,19 +36,19 @@
 public class RestrictionEntry implements Parcelable {
 
     /**
-     * A type of restriction. Use this type for information that needs to be transferred across
-     * but shouldn't be presented to the user in the UI. Stores a single String value.
+     * Hidden restriction type. Use this type for information that needs to be transferred
+     * across but shouldn't be presented to the user in the UI. Stores a single String value.
      */
     public static final int TYPE_NULL         = 0;
 
     /**
-     * A type of restriction. Use this for storing a boolean value, typically presented as
+     * Restriction of type "bool". Use this for storing a boolean value, typically presented as
      * a checkbox in the UI.
      */
     public static final int TYPE_BOOLEAN      = 1;
 
     /**
-     * A type of restriction. Use this for storing a string value, typically presented as
+     * Restriction of type "choice". Use this for storing a string value, typically presented as
      * a single-select list. Call {@link #setChoiceEntries(String[])} and
      * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
      * and the corresponding values, respectively.
@@ -53,7 +56,7 @@
     public static final int TYPE_CHOICE       = 2;
 
     /**
-     * A type of restriction. Use this for storing a string value, typically presented as
+     * Internal restriction type. Use this for storing a string value, typically presented as
      * a single-select list. Call {@link #setChoiceEntries(String[])} and
      * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
      * and the corresponding values, respectively.
@@ -64,8 +67,8 @@
     public static final int TYPE_CHOICE_LEVEL = 3;
 
     /**
-     * A type of restriction. Use this for presenting a multi-select list where more than one
-     * entry can be selected, such as for choosing specific titles to white-list.
+     * Restriction of type "multi-select". Use this for presenting a multi-select list where more
+     * than one entry can be selected, such as for choosing specific titles to white-list.
      * Call {@link #setChoiceEntries(String[])} and
      * {@link #setChoiceValues(String[])} to set the localized list entries to present to the user
      * and the corresponding values, respectively.
@@ -75,18 +78,30 @@
     public static final int TYPE_MULTI_SELECT = 4;
 
     /**
-     * A type of restriction. Use this for storing an integer value. The range of values
+     * Restriction of type "integer". Use this for storing an integer value. The range of values
      * is from {@link Integer#MIN_VALUE} to {@link Integer#MAX_VALUE}.
      */
     public static final int TYPE_INTEGER = 5;
 
     /**
-     * A type of restriction. Use this for storing a string value.
+     * Restriction of type "string". Use this for storing a string value.
      * @see #setSelectedString
      * @see #getSelectedString
      */
     public static final int TYPE_STRING = 6;
 
+    /**
+     * Restriction of type "bundle". Use this for storing {@link android.os.Bundle bundles} of
+     * restrictions
+     */
+    public static final int TYPE_BUNDLE = 7;
+
+    /**
+     * Restriction of type "bundle_array". Use this for storing arrays of
+     * {@link android.os.Bundle bundles} of restrictions
+     */
+    public static final int TYPE_BUNDLE_ARRAY = 8;
+
     /** The type of restriction. */
     private int mType;
 
@@ -100,13 +115,13 @@
     private String mDescription;
 
     /** The user-visible set of choices used for single-select and multi-select lists. */
-    private String [] mChoiceEntries;
+    private String[] mChoiceEntries;
 
     /** The values corresponding to the user-visible choices. The value(s) of this entry will
      * one or more of these, returned by {@link #getAllSelectedStrings()} and
      * {@link #getSelectedString()}.
      */
-    private String [] mChoiceValues;
+    private String[] mChoiceValues;
 
     /* The chosen value, whose content depends on the type of the restriction. */
     private String mCurrentValue;
@@ -115,6 +130,12 @@
     private String[] mCurrentValues;
 
     /**
+     * List of nested restrictions. Used by {@link #TYPE_BUNDLE bundle} and
+     * {@link #TYPE_BUNDLE_ARRAY bundle_array} restrictions.
+     */
+    private RestrictionEntry[] mRestrictions;
+
+    /**
      * Constructor for specifying the type and key, with no initial value;
      *
      * @param type the restriction type.
@@ -170,6 +191,35 @@
     }
 
     /**
+     * Constructor for {@link #TYPE_BUNDLE}/{@link #TYPE_BUNDLE_ARRAY} type.
+     * @param key the unique key for this restriction
+     * @param restrictionEntries array of nested restriction entries. If the entry, being created
+     * represents a {@link #TYPE_BUNDLE_ARRAY bundle-array}, {@code restrictionEntries} array may
+     * only contain elements of type {@link #TYPE_BUNDLE bundle}.
+     * @param isBundleArray true if this restriction represents
+     * {@link #TYPE_BUNDLE_ARRAY bundle-array} type, otherwise the type will be set to
+     * {@link #TYPE_BUNDLE bundle}.
+     */
+    public RestrictionEntry(String key, RestrictionEntry[] restrictionEntries,
+            boolean isBundleArray) {
+        mKey = key;
+        if (isBundleArray) {
+            mType = TYPE_BUNDLE_ARRAY;
+            if (restrictionEntries != null) {
+                for (RestrictionEntry restriction : restrictionEntries) {
+                    if (restriction.getType() != TYPE_BUNDLE) {
+                        throw new IllegalArgumentException("bundle_array restriction can only have "
+                                + "nested restriction entries of type bundle");
+                    }
+                }
+            }
+        } else {
+            mType = TYPE_BUNDLE;
+        }
+        setRestrictions(restrictionEntries);
+    }
+
+    /**
      * Sets the type for this restriction.
      * @param type the type for this restriction.
      */
@@ -283,6 +333,22 @@
     }
 
     /**
+     * Returns array of possible restriction entries that this entry may contain.
+     */
+    public RestrictionEntry[] getRestrictions() {
+        return mRestrictions;
+    }
+
+   /**
+    * Sets an array of possible restriction entries, that this entry may contain.
+    * <p>This method is only relevant for types {@link #TYPE_BUNDLE} and
+    * {@link #TYPE_BUNDLE_ARRAY}
+    */
+    public void setRestrictions(RestrictionEntry[] restrictions) {
+        mRestrictions = restrictions;
+    }
+
+    /**
      * Returns the list of possible string values set earlier.
      * @return the list of possible values.
      */
@@ -362,27 +428,30 @@
         this.mTitle = title;
     }
 
-    private boolean equalArrays(String[] one, String[] other) {
-        if (one.length != other.length) return false;
-        for (int i = 0; i < one.length; i++) {
-            if (!one[i].equals(other[i])) return false;
-        }
-        return true;
-    }
-
     @Override
     public boolean equals(Object o) {
         if (o == this) return true;
         if (!(o instanceof RestrictionEntry)) return false;
         final RestrictionEntry other = (RestrictionEntry) o;
-        // Make sure that either currentValue matches or currentValues matches.
-        return mType == other.mType && mKey.equals(other.mKey)
-                &&
-                ((mCurrentValues == null && other.mCurrentValues == null
-                  && mCurrentValue != null && mCurrentValue.equals(other.mCurrentValue))
-                 ||
-                 (mCurrentValue == null && other.mCurrentValue == null
-                  && mCurrentValues != null && equalArrays(mCurrentValues, other.mCurrentValues)));
+        if (mType != other.mType || mKey.equals(other.mKey)) {
+            return false;
+        }
+        if (mCurrentValues == null && other.mCurrentValues == null
+                && mRestrictions == null && other.mRestrictions == null
+                && Objects.equals(mCurrentValue, other.mCurrentValue)) {
+            return true;
+        }
+        if (mCurrentValue == null && other.mCurrentValue == null
+                && mRestrictions == null && other.mRestrictions == null
+                && Arrays.equals(mCurrentValues, other.mCurrentValues)) {
+            return true;
+        }
+        if (mCurrentValue == null && other.mCurrentValue == null
+                && mCurrentValue == null && other.mCurrentValue == null
+                && Arrays.equals(mRestrictions, other.mRestrictions)) {
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -397,28 +466,28 @@
                     result = 31 * result + value.hashCode();
                 }
             }
+        } else if (mRestrictions != null) {
+            result = 31 * result + Arrays.hashCode(mRestrictions);
         }
         return result;
     }
 
-    private String[] readArray(Parcel in) {
-        int count = in.readInt();
-        String[] values = new String[count];
-        for (int i = 0; i < count; i++) {
-            values[i] = in.readString();
-        }
-        return values;
-    }
-
     public RestrictionEntry(Parcel in) {
         mType = in.readInt();
         mKey = in.readString();
         mTitle = in.readString();
         mDescription = in.readString();
-        mChoiceEntries = readArray(in);
-        mChoiceValues = readArray(in);
+        mChoiceEntries = in.readStringArray();
+        mChoiceValues = in.readStringArray();
         mCurrentValue = in.readString();
-        mCurrentValues = readArray(in);
+        mCurrentValues = in.readStringArray();
+        Parcelable[] parcelables = in.readParcelableArray(null);
+        if (parcelables != null) {
+            mRestrictions = new RestrictionEntry[parcelables.length];
+            for (int i = 0; i < parcelables.length; i++) {
+                mRestrictions[i] = (RestrictionEntry) parcelables[i];
+            }
+        }
     }
 
     @Override
@@ -426,27 +495,17 @@
         return 0;
     }
 
-    private void writeArray(Parcel dest, String[] values) {
-        if (values == null) {
-            dest.writeInt(0);
-        } else {
-            dest.writeInt(values.length);
-            for (int i = 0; i < values.length; i++) {
-                dest.writeString(values[i]);
-            }
-        }
-    }
-
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(mType);
         dest.writeString(mKey);
         dest.writeString(mTitle);
         dest.writeString(mDescription);
-        writeArray(dest, mChoiceEntries);
-        writeArray(dest, mChoiceValues);
+        dest.writeStringArray(mChoiceEntries);
+        dest.writeStringArray(mChoiceValues);
         dest.writeString(mCurrentValue);
-        writeArray(dest, mCurrentValues);
+        dest.writeStringArray(mCurrentValues);
+        dest.writeParcelableArray(mRestrictions, 0);
     }
 
     public static final Creator<RestrictionEntry> CREATOR = new Creator<RestrictionEntry>() {
@@ -461,6 +520,16 @@
 
     @Override
     public String toString() {
-        return "RestrictionsEntry {type=" + mType + ", key=" + mKey + ", value=" + mCurrentValue + "}";
+        return "RestrictionEntry{" +
+                "mType=" + mType +
+                ", mKey='" + mKey + '\'' +
+                ", mTitle='" + mTitle + '\'' +
+                ", mDescription='" + mDescription + '\'' +
+                ", mChoiceEntries=" + Arrays.toString(mChoiceEntries) +
+                ", mChoiceValues=" + Arrays.toString(mChoiceValues) +
+                ", mCurrentValue='" + mCurrentValue + '\'' +
+                ", mCurrentValues=" + Arrays.toString(mCurrentValues) +
+                ", mRestrictions=" + Arrays.toString(mRestrictions) +
+                '}';
     }
 }
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 21a6a0d..1fac06e 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -32,12 +32,14 @@
 import android.util.Xml;
 
 import com.android.internal.R;
+import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -71,12 +73,15 @@
  *         android:key="string"
  *         android:title="string resource"
  *         android:restrictionType=["bool" | "string" | "integer"
- *                                         | "choice" | "multi-select" | "hidden"]
+ *                                         | "choice" | "multi-select" | "hidden"
+ *                                         | "bundle" | "bundle_array"]
  *         android:description="string resource"
  *         android:entries="string-array resource"
  *         android:entryValues="string-array resource"
- *         android:defaultValue="reference"
- *         /&gt;
+ *         android:defaultValue="reference" &gt;
+ *             &lt;restriction ... /&gt;
+ *             ...
+ *     &lt;/restriction&gt;
  *     &lt;restriction ... /&gt;
  *     ...
  * &lt;/restrictions&gt;
@@ -97,6 +102,9 @@
  * administrator controlling the values, if the title is not sufficient.</li>
  * </ul>
  * <p>
+ * Only restrictions of type {@code bundle} and {@code bundle_array} can have one or multiple nested
+ * restriction elements.
+ * <p>
  * In your manifest's <code>application</code> section, add the meta-data tag to point to
  * the restrictions XML file as shown below:
  * <pre>
@@ -537,9 +545,7 @@
 
         XmlResourceParser xml =
                 appInfo.loadXmlMetaData(mContext.getPackageManager(), META_DATA_APP_RESTRICTIONS);
-        List<RestrictionEntry> restrictions = loadManifestRestrictions(packageName, xml);
-
-        return restrictions;
+        return loadManifestRestrictions(packageName, xml);
     }
 
     private List<RestrictionEntry> loadManifestRestrictions(String packageName,
@@ -550,23 +556,16 @@
         } catch (NameNotFoundException nnfe) {
             return null;
         }
-        ArrayList<RestrictionEntry> restrictions = new ArrayList<RestrictionEntry>();
+        ArrayList<RestrictionEntry> restrictions = new ArrayList<>();
         RestrictionEntry restriction;
 
         try {
             int tagType = xml.next();
             while (tagType != XmlPullParser.END_DOCUMENT) {
                 if (tagType == XmlPullParser.START_TAG) {
-                    if (xml.getName().equals(TAG_RESTRICTION)) {
-                        AttributeSet attrSet = Xml.asAttributeSet(xml);
-                        if (attrSet != null) {
-                            TypedArray a = appContext.obtainStyledAttributes(attrSet,
-                                    com.android.internal.R.styleable.RestrictionEntry);
-                            restriction = loadRestriction(appContext, a);
-                            if (restriction != null) {
-                                restrictions.add(restriction);
-                            }
-                        }
+                    restriction = loadRestrictionElement(appContext, xml);
+                    if (restriction != null) {
+                        restrictions.add(restriction);
                     }
                 }
                 tagType = xml.next();
@@ -582,7 +581,21 @@
         return restrictions;
     }
 
-    private RestrictionEntry loadRestriction(Context appContext, TypedArray a) {
+    private RestrictionEntry loadRestrictionElement(Context appContext, XmlResourceParser xml)
+            throws IOException, XmlPullParserException {
+        if (xml.getName().equals(TAG_RESTRICTION)) {
+            AttributeSet attrSet = Xml.asAttributeSet(xml);
+            if (attrSet != null) {
+                TypedArray a = appContext.obtainStyledAttributes(attrSet,
+                        com.android.internal.R.styleable.RestrictionEntry);
+                return loadRestriction(appContext, a, xml);
+            }
+        }
+        return null;
+    }
+
+    private RestrictionEntry loadRestriction(Context appContext, TypedArray a, XmlResourceParser xml)
+            throws IOException, XmlPullParserException {
         String key = a.getString(R.styleable.RestrictionEntry_key);
         int restrictionType = a.getInt(
                 R.styleable.RestrictionEntry_restrictionType, -1);
@@ -633,9 +646,90 @@
                 restriction.setSelectedState(
                         a.getBoolean(R.styleable.RestrictionEntry_defaultValue, false));
                 break;
+            case RestrictionEntry.TYPE_BUNDLE:
+            case RestrictionEntry.TYPE_BUNDLE_ARRAY:
+                final int outerDepth = xml.getDepth();
+                List<RestrictionEntry> restrictionEntries = new ArrayList<>();
+                while (XmlUtils.nextElementWithin(xml, outerDepth)) {
+                    RestrictionEntry childEntry = loadRestrictionElement(appContext, xml);
+                    if (childEntry == null) {
+                        Log.w(TAG, "Child entry cannot be loaded for bundle restriction " + key);
+                    } else {
+                        restrictionEntries.add(childEntry);
+                        if (restrictionType == RestrictionEntry.TYPE_BUNDLE_ARRAY
+                                && childEntry.getType() != RestrictionEntry.TYPE_BUNDLE) {
+                            Log.w(TAG, "bundle_array " + key
+                                    + " can only contain entries of type bundle");
+                        }
+                    }
+                }
+                restriction.setRestrictions(restrictionEntries.toArray(new RestrictionEntry[
+                        restrictionEntries.size()]));
+                break;
             default:
                 Log.w(TAG, "Unknown restriction type " + restrictionType);
         }
         return restriction;
     }
+
+    /**
+     * Converts a list of restrictions to the corresponding bundle, using the following mapping:
+     * <table>
+     *     <tr><th>RestrictionEntry</th><th>Bundle</th></tr>
+     *     <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr>
+     *     <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td>
+     *     <td>{@link Bundle#putStringArray}</td></tr>
+     *     <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr>
+     *     <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr>
+     *     <tr><td>{@link RestrictionEntry#TYPE_BUNDLE}</td><td>{@link Bundle#putBundle}</td></tr>
+     *     <tr><td>{@link RestrictionEntry#TYPE_BUNDLE_ARRAY}</td>
+     *     <td>{@link Bundle#putParcelableArray}</td></tr>
+     * </table>
+     * @param entries list of restrictions
+     */
+    public static Bundle convertRestrictionsToBundle(List<RestrictionEntry> entries) {
+        final Bundle bundle = new Bundle();
+        for (RestrictionEntry entry : entries) {
+            addRestrictionToBundle(bundle, entry);
+        }
+        return bundle;
+    }
+
+    private static Bundle addRestrictionToBundle(Bundle bundle, RestrictionEntry entry) {
+        switch (entry.getType()) {
+            case RestrictionEntry.TYPE_BOOLEAN:
+                bundle.putBoolean(entry.getKey(), entry.getSelectedState());
+                break;
+            case RestrictionEntry.TYPE_CHOICE:
+            case RestrictionEntry.TYPE_CHOICE_LEVEL:
+            case RestrictionEntry.TYPE_MULTI_SELECT:
+                bundle.putStringArray(entry.getKey(), entry.getAllSelectedStrings());
+                break;
+            case RestrictionEntry.TYPE_INTEGER:
+                bundle.putInt(entry.getKey(), entry.getIntValue());
+                break;
+            case RestrictionEntry.TYPE_STRING:
+            case RestrictionEntry.TYPE_NULL:
+                bundle.putString(entry.getKey(), entry.getSelectedString());
+                break;
+            case RestrictionEntry.TYPE_BUNDLE:
+                RestrictionEntry[] restrictions = entry.getRestrictions();
+                Bundle childBundle = convertRestrictionsToBundle(Arrays.asList(restrictions));
+                bundle.putBundle(entry.getKey(), childBundle);
+                break;
+            case RestrictionEntry.TYPE_BUNDLE_ARRAY:
+                restrictions = entry.getRestrictions();
+                Bundle[] bundleArray = new Bundle[restrictions.length];
+                for (int i = 0; i < restrictions.length; i++) {
+                    bundleArray[i] = addRestrictionToBundle(new Bundle(), restrictions[i]);
+                }
+                bundle.putParcelableArray(entry.getKey(), bundleArray);
+                break;
+            default:
+                throw new IllegalArgumentException(
+                        "Unsupported restrictionEntry type: " + entry.getType());
+        }
+        return bundle;
+    }
+
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 2496e45..5bdb7bb 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -421,6 +421,14 @@
     public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
 
     /**
+     * Value for {@link #flags}: {@code true} if the application has any IntentFiler with some
+     * data URI using HTTP or HTTPS with an associated VIEW action.
+     *
+     * {@hide}
+     */
+    public static final int PRIVATE_FLAG_HAS_DOMAIN_URLS = 1<<4;
+
+    /**
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * {@hide}
      */
@@ -451,6 +459,8 @@
     public int largestWidthLimitDp = 0;
 
     /** {@hide} */
+    public String volumeUuid;
+    /** {@hide} */
     public String scanSourceDir;
     /** {@hide} */
     public String scanPublicSourceDir;
@@ -718,6 +728,7 @@
         requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
         compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
         largestWidthLimitDp = orig.largestWidthLimitDp;
+        volumeUuid = orig.volumeUuid;
         scanSourceDir = orig.scanSourceDir;
         scanPublicSourceDir = orig.scanPublicSourceDir;
         sourceDir = orig.sourceDir;
@@ -770,6 +781,7 @@
         dest.writeInt(requiresSmallestWidthDp);
         dest.writeInt(compatibleWidthLimitDp);
         dest.writeInt(largestWidthLimitDp);
+        dest.writeString(volumeUuid);
         dest.writeString(scanSourceDir);
         dest.writeString(scanPublicSourceDir);
         dest.writeString(sourceDir);
@@ -821,6 +833,7 @@
         requiresSmallestWidthDp = source.readInt();
         compatibleWidthLimitDp = source.readInt();
         largestWidthLimitDp = source.readInt();
+        volumeUuid = source.readString();
         scanSourceDir = source.readString();
         scanPublicSourceDir = source.readString();
         sourceDir = source.readString();
@@ -913,6 +926,20 @@
     /**
      * @hide
      */
+    public boolean isSystemApp() {
+        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isUpdatedSystemApp() {
+        return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
+    }
+
+    /**
+     * @hide
+     */
     @Override protected ApplicationInfo getApplicationInfo() {
         return this;
     }
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index ba62cd6..154ff85 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -44,7 +44,8 @@
     void registerCallback(IPackageInstallerCallback callback, int userId);
     void unregisterCallback(IPackageInstallerCallback callback);
 
-    void uninstall(String packageName, int flags, in IntentSender statusReceiver, int userId);
+    void uninstall(String packageName, String callerPackageName, int flags,
+            in IntentSender statusReceiver, int userId);
 
     void setPermissionsResult(int sessionId, boolean accepted);
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 66b0d1a..c2580c0 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -269,6 +269,12 @@
     void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage);
 
     /**
+     * Backup/restore support - only the system uid may use these.
+     */
+    byte[] getPreferredActivityBackup(int userId);
+    void restorePreferredActivities(in byte[] backup, int userId);
+
+    /**
      * Report the set of 'Home' activity candidates, plus (if any) which of them
      * is the current "always use this one" setting.
      */
@@ -426,7 +432,8 @@
     PackageCleanItem nextPackageToClean(in PackageCleanItem lastPackage);
 
     void movePackage(String packageName, IPackageMoveObserver observer, int flags);
-    
+    void movePackageAndData(String packageName, String volumeUuid, IPackageMoveObserver observer);
+
     boolean addPermissionAsync(in PermissionInfo info);
 
     boolean setInstallLocation(int loc);
@@ -437,10 +444,14 @@
     void verifyPendingInstall(int id, int verificationCode);
     void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
 
-    void verifyIntentFilter(int id, int verificationCode, in List<String> outFailedDomains);
+    void verifyIntentFilter(int id, int verificationCode, in List<String> failedDomains);
     int getIntentVerificationStatus(String packageName, int userId);
     boolean updateIntentVerificationStatus(String packageName, int status, int userId);
     List<IntentFilterVerificationInfo> getIntentFilterVerifications(String packageName);
+    List<IntentFilter> getAllIntentFilters(String packageName);
+
+    boolean setDefaultBrowserPackageName(String packageName, int userId);
+    String getDefaultBrowserPackageName(int userId);
 
     VerifierDeviceIdentity getVerifierDeviceIdentity();
 
diff --git a/core/java/android/content/pm/IntentFilterVerificationInfo.java b/core/java/android/content/pm/IntentFilterVerificationInfo.java
index 60cb4a8..e50b0ff 100644
--- a/core/java/android/content/pm/IntentFilterVerificationInfo.java
+++ b/core/java/android/content/pm/IntentFilterVerificationInfo.java
@@ -24,6 +24,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import com.android.internal.util.XmlUtils;
 import org.xmlpull.v1.XmlPullParser;
@@ -35,7 +36,7 @@
 
 /**
  * The {@link com.android.server.pm.PackageManagerService} maintains some
- * {@link IntentFilterVerificationInfo}s for each domain / package / class name per user.
+ * {@link IntentFilterVerificationInfo}s for each domain / package name.
  *
  * @hide
  */
@@ -47,17 +48,17 @@
     private static final String ATTR_PACKAGE_NAME = "packageName";
     private static final String ATTR_STATUS = "status";
 
-    private String[] mDomains;
+    private ArrayList<String> mDomains;
     private String mPackageName;
     private int mMainStatus;
 
     public IntentFilterVerificationInfo() {
         mPackageName = null;
-        mDomains = new String[0];
+        mDomains = new ArrayList<>();
         mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
 
-    public IntentFilterVerificationInfo(String packageName, String[] domains) {
+    public IntentFilterVerificationInfo(String packageName, ArrayList<String> domains) {
         mPackageName = packageName;
         mDomains = domains;
         mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
@@ -72,10 +73,14 @@
         readFromParcel(source);
     }
 
-    public String[] getDomains() {
+    public ArrayList<String> getDomains() {
         return mDomains;
     }
 
+    public ArraySet<String> getDomainsSet() {
+        return new ArraySet<>(mDomains);
+    }
+
     public String getPackageName() {
         return mPackageName;
     }
@@ -140,7 +145,7 @@
         }
         mMainStatus = status;
 
-        ArrayList<String> list = new ArrayList<>();
+        mDomains = new ArrayList<>();
         int outerDepth = parser.getDepth();
         int type;
         while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -155,18 +160,13 @@
             if (tagName.equals(TAG_DOMAIN)) {
                 String name = getStringFromXml(parser, ATTR_DOMAIN_NAME, null);
                 if (!TextUtils.isEmpty(name)) {
-                    if (list == null) {
-                        list = new ArrayList<>();
-                    }
-                    list.add(name);
+                    mDomains.add(name);
                 }
             } else {
                 Log.w(TAG, "Unknown tag parsing IntentFilter: " + tagName);
             }
             XmlUtils.skipCurrentTag(parser);
         }
-
-        mDomains = list.toArray(new String[list.size()]);
     }
 
     public void writeToXml(XmlSerializer serializer) throws IOException {
@@ -201,14 +201,15 @@
     private void readFromParcel(Parcel source) {
         mPackageName = source.readString();
         mMainStatus = source.readInt();
-        mDomains = source.readStringArray();
+        mDomains = new ArrayList<>();
+        source.readStringList(mDomains);
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mPackageName);
         dest.writeInt(mMainStatus);
-        dest.writeStringArray(mDomains);
+        dest.writeStringList(mDomains);
     }
 
     public static final Creator<IntentFilterVerificationInfo> CREATOR =
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 80efd0b..b7ee82d 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -423,7 +423,7 @@
      */
     public void uninstall(@NonNull String packageName, @NonNull IntentSender statusReceiver) {
         try {
-            mInstaller.uninstall(packageName, 0, statusReceiver, mUserId);
+            mInstaller.uninstall(packageName, mInstallerPackageName, 0, statusReceiver, mUserId);
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -887,6 +887,8 @@
         public Uri referrerUri;
         /** {@hide} */
         public String abiOverride;
+        /** {@hide} */
+        public String volumeUuid;
 
         /**
          * Construct parameters for a new package install session.
@@ -911,6 +913,7 @@
             originatingUri = source.readParcelable(null);
             referrerUri = source.readParcelable(null);
             abiOverride = source.readString();
+            volumeUuid = source.readString();
         }
 
         /**
@@ -1008,6 +1011,7 @@
             pw.printPair("originatingUri", originatingUri);
             pw.printPair("referrerUri", referrerUri);
             pw.printPair("abiOverride", abiOverride);
+            pw.printPair("volumeUuid", volumeUuid);
             pw.println();
         }
 
@@ -1028,6 +1032,7 @@
             dest.writeParcelable(originatingUri, flags);
             dest.writeParcelable(referrerUri, flags);
             dest.writeString(abiOverride);
+            dest.writeString(volumeUuid);
         }
 
         public static final Parcelable.Creator<SessionParams>
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 46d6ffb3..0396660 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -43,7 +43,9 @@
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.storage.VolumeInfo;
 import android.util.AndroidException;
+
 import com.android.internal.util.ArrayUtils;
 
 import java.io.File;
@@ -339,15 +341,17 @@
     public static final int INSTALL_ALLOW_TEST = 0x00000004;
 
     /**
-     * Flag parameter for {@link #installPackage} to indicate that this
-     * package has to be installed on the sdcard.
+     * Flag parameter for {@link #installPackage} to indicate that this package
+     * must be installed to an ASEC on a {@link VolumeInfo#TYPE_PUBLIC}.
+     *
      * @hide
      */
     public static final int INSTALL_EXTERNAL = 0x00000008;
 
     /**
      * Flag parameter for {@link #installPackage} to indicate that this package
-     * has to be installed on the sdcard.
+     * must be installed to internal storage.
+     *
      * @hide
      */
     public static final int INSTALL_INTERNAL = 0x00000010;
@@ -1314,6 +1318,15 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports high fidelity sensor processing
+     * capabilities.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_HIFI_SENSORS =
+            "android.hardware.sensor.hifi_sensors";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device has a telephony radio with data
      * communication support.
      */
@@ -3631,13 +3644,55 @@
      * @param packageName the package name. When this parameter is set to a non null value,
      *                    the results will be filtered by the package name provided.
      *                    Otherwise, there will be no filtering and it will return a list
-     *                    corresponding for all packages for the provided userId.
-     * @return a list of IntentFilterVerificationInfo for a specific package and User.
+     *                    corresponding for all packages
+     *
+     * @return a list of IntentFilterVerificationInfo for a specific package.
+     *
+     * @hide
      */
     public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
             String packageName);
 
     /**
+     * Get the list of IntentFilter for a specific package.
+     *
+     * @param packageName the package name. This parameter is set to a non null value,
+     *                    the list will contain all the IntentFilter for that package.
+     *                    Otherwise, the list will be empty.
+     *
+     * @return a list of IntentFilter for a specific package.
+     *
+     * @hide
+     */
+    public abstract List<IntentFilter> getAllIntentFilters(String packageName);
+
+    /**
+     * Get the default Browser package name for a specific user.
+     *
+     * @param userId The user id.
+     *
+     * @return the package name of the default Browser for the specified user. If the user id passed
+     *         is -1 (all users) it will return a null value.
+     *
+     * @hide
+     */
+    public abstract String getDefaultBrowserPackageName(int userId);
+
+    /**
+     * Set the default Browser package name for a specific user.
+     *
+     * @param packageName The package name of the default Browser.
+     * @param userId The user id.
+     *
+     * @return true if the default Browser for the specified user has been set,
+     *         otherwise return false. If the user id passed is -1 (all users) this call will not
+     *         do anything and just return false.
+     *
+     * @hide
+     */
+    public abstract boolean setDefaultBrowserPackageName(String packageName, int userId);
+
+    /**
      * Change the installer associated with a given package.  There are limitations
      * on how the installer package can be changed; in particular:
      * <ul>
@@ -4099,8 +4154,12 @@
      *
      * @hide
      */
-    public abstract void movePackage(
-            String packageName, IPackageMoveObserver observer, int flags);
+    @Deprecated
+    public abstract void movePackage(String packageName, IPackageMoveObserver observer, int flags);
+
+    /** {@hide} */
+    public abstract void movePackageAndData(String packageName, String volumeUuid,
+            IPackageMoveObserver observer);
 
     /**
      * Returns the device identity that verifiers can use to associate their scheme to a particular
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 4b81fd4..7523675 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -604,7 +604,7 @@
     public final static int PARSE_MUST_BE_APK = 1<<2;
     public final static int PARSE_IGNORE_PROCESSES = 1<<3;
     public final static int PARSE_FORWARD_LOCK = 1<<4;
-    public final static int PARSE_ON_SDCARD = 1<<5;
+    public final static int PARSE_EXTERNAL_STORAGE = 1<<5;
     public final static int PARSE_IS_SYSTEM_DIR = 1<<6;
     public final static int PARSE_IS_PRIVILEGED = 1<<7;
     public final static int PARSE_COLLECT_CERTIFICATES = 1<<8;
@@ -1408,7 +1408,7 @@
         }
 
         /* Set the global "on SD card" flag */
-        if ((flags & PARSE_ON_SDCARD) != 0) {
+        if ((flags & PARSE_EXTERNAL_STORAGE) != 0) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
         }
 
@@ -1487,7 +1487,11 @@
                     return null;
                 }
             } else if (tagName.equals("uses-permission")) {
-                if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
+                if (!parseUsesPermission(pkg, res, parser, attrs)) {
+                    return null;
+                }
+            } else if (tagName.equals("uses-permission-sdk-m")) {
+                if (!parseUsesPermission(pkg, res, parser, attrs)) {
                     return null;
                 }
             } else if (tagName.equals("uses-configuration")) {
@@ -1887,8 +1891,7 @@
     }
 
     private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser,
-                                        AttributeSet attrs, String[] outError)
-            throws XmlPullParserException, IOException {
+            AttributeSet attrs) throws XmlPullParserException, IOException {
         TypedArray sa = res.obtainAttributes(attrs,
                 com.android.internal.R.styleable.AndroidManifestUsesPermission);
 
@@ -1914,8 +1917,9 @@
                 if (index == -1) {
                     pkg.requestedPermissions.add(name.intern());
                 } else {
-                    Slog.w(TAG, "Ignoring duplicate uses-permission: " + name + " in package: "
-                            + pkg.packageName + " at: " + parser.getPositionDescription());
+                    Slog.w(TAG, "Ignoring duplicate uses-permissions/uses-permissions-sdk-m: "
+                            + name + " in package: " + pkg.packageName + " at: "
+                            + parser.getPositionDescription());
                 }
             }
         }
@@ -2752,6 +2756,12 @@
 
         modifySharedLibrariesForBackwardCompatibility(owner);
 
+        if (hasDomainURLs(owner)) {
+            owner.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
+        } else {
+            owner.applicationInfo.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS;
+        }
+
         return true;
     }
 
@@ -2768,6 +2778,32 @@
     }
 
     /**
+     * Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
+     */
+    private static boolean hasDomainURLs(Package pkg) {
+        if (pkg == null || pkg.activities == null) return false;
+        final ArrayList<Activity> activities = pkg.activities;
+        final int countActivities = activities.size();
+        for (int n=0; n<countActivities; n++) {
+            Activity activity = activities.get(n);
+            ArrayList<ActivityIntentInfo> filters = activity.intents;
+            if (filters == null) continue;
+            final int countFilters = filters.size();
+            for (int m=0; m<countFilters; m++) {
+                ActivityIntentInfo aii = filters.get(m);
+                if (!aii.hasAction(Intent.ACTION_VIEW)) continue;
+                if (!aii.hasAction(Intent.ACTION_DEFAULT)) continue;
+                if (aii.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                        aii.hasDataScheme(IntentFilter.SCHEME_HTTPS)) {
+                    Slog.d(TAG, "hasDomainURLs:true for package:" + pkg.packageName);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Parse the {@code application} XML tree at the current parse location in a
      * <em>split APK</em> manifest.
      * <p>
@@ -4411,6 +4447,20 @@
             return applicationInfo.isForwardLocked();
         }
 
+        /**
+         * @hide
+         */
+        public boolean isSystemApp() {
+            return applicationInfo.isSystemApp();
+        }
+
+        /**
+         * @hide
+         */
+        public boolean isUpdatedSystemApp() {
+            return applicationInfo.isUpdatedSystemApp();
+        }
+
         public String toString() {
             return "Package{"
                 + Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 7b141f0..05f5e90 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -144,9 +144,9 @@
     public boolean system;
 
     /**
-     * @hide Does the associated IntentFilter needs verification ?
+     * @hide Does the associated IntentFilter comes from a Browser ?
      */
-    public boolean filterNeedsVerification;
+    public boolean handleAllWebDataURI;
 
     private ComponentInfo getComponentInfo() {
         if (activityInfo != null) return activityInfo;
@@ -288,7 +288,7 @@
         resolvePackageName = orig.resolvePackageName;
         system = orig.system;
         targetUserId = orig.targetUserId;
-        filterNeedsVerification = orig.filterNeedsVerification;
+        handleAllWebDataURI = orig.handleAllWebDataURI;
     }
 
     public String toString() {
@@ -350,7 +350,7 @@
         dest.writeInt(targetUserId);
         dest.writeInt(system ? 1 : 0);
         dest.writeInt(noResourceId ? 1 : 0);
-        dest.writeInt(filterNeedsVerification ? 1 : 0);
+        dest.writeInt(handleAllWebDataURI ? 1 : 0);
     }
 
     public static final Creator<ResolveInfo> CREATOR
@@ -396,7 +396,7 @@
         targetUserId = source.readInt();
         system = source.readInt() != 0;
         noResourceId = source.readInt() != 0;
-        filterNeedsVerification = source.readInt() != 0;
+        handleAllWebDataURI = source.readInt() != 0;
     }
     
     public static class DisplayNameComparator
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index 7d8dff3..fdafb04 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -71,10 +71,15 @@
  */
 public class ColorStateList implements Parcelable {
     private static final String TAG = "ColorStateList";
+
     private static final int DEFAULT_COLOR = Color.RED;
     private static final int[][] EMPTY = new int[][] { new int[0] };
-    private static final SparseArray<WeakReference<ColorStateList>> sCache =
-                            new SparseArray<WeakReference<ColorStateList>>();
+
+    /** Thread-safe cache of single-color ColorStateLists. */
+    private static final SparseArray<WeakReference<ColorStateList>> sCache = new SparseArray<>();
+
+    /** Lazily-created factory for this color state list. */
+    private ColorStateListFactory mFactory;
 
     private int[][] mThemeAttrs;
     private int mChangingConfigurations;
@@ -125,7 +130,7 @@
             }
 
             final ColorStateList csl = new ColorStateList(EMPTY, new int[] { color });
-            sCache.put(color, new WeakReference<ColorStateList>(csl));
+            sCache.put(color, new WeakReference<>(csl));
             return csl;
         }
     }
@@ -141,11 +146,13 @@
      */
     private ColorStateList(ColorStateList orig) {
         if (orig != null) {
+            mChangingConfigurations = orig.mChangingConfigurations;
             mStateSpecs = orig.mStateSpecs;
             mDefaultColor = orig.mDefaultColor;
             mIsOpaque = orig.mIsOpaque;
 
-            // Deep copy, this may change due to theming.
+            // Deep copy, these may change due to applyTheme().
+            mThemeAttrs = orig.mThemeAttrs.clone();
             mColors = orig.mColors.clone();
         }
     }
@@ -329,6 +336,7 @@
      * attributes.
      *
      * @return whether a theme can be applied to this color state list
+     * @hide only for resource preloading
      */
     public boolean canApplyTheme() {
         return mThemeAttrs != null;
@@ -336,10 +344,15 @@
 
     /**
      * Applies a theme to this color state list.
+     * <p>
+     * <strong>Note:</strong> Applying a theme may affect the changing
+     * configuration parameters of this color state list. After calling this
+     * method, any dependent configurations must be updated by obtaining the
+     * new configuration mask from {@link #getChangingConfigurations()}.
      *
      * @param t the theme to apply
      */
-    public void applyTheme(Theme t) {
+    private void applyTheme(Theme t) {
         if (mThemeAttrs == null) {
             return;
         }
@@ -376,6 +389,38 @@
         onColorsChanged();
     }
 
+    /**
+     * Returns an appropriately themed color state list.
+     *
+     * @param t the theme to apply
+     * @return a copy of the color state list with the theme applied, or the
+     *         color state list itself if there were no unresolved theme
+     *         attributes
+     * @hide only for resource preloading
+     */
+    public ColorStateList obtainForTheme(Theme t) {
+        if (t == null || !canApplyTheme()) {
+            return this;
+        }
+
+        final ColorStateList clone = new ColorStateList(this);
+        clone.applyTheme(t);
+        return clone;
+    }
+
+    /**
+     * Returns a mask of the configuration parameters for which this color
+     * state list may change, requiring that it be re-created.
+     *
+     * @return a mask of the changing configuration parameters, as defined by
+     *         {@link android.content.pm.ActivityInfo}
+     *
+     * @see android.content.pm.ActivityInfo
+     */
+    public int getChangingConfigurations() {
+        return mChangingConfigurations;
+    }
+
     private int modulateColorAlpha(int baseColor, float alphaMod) {
         if (alphaMod == 1.0f) {
             return baseColor;
@@ -383,8 +428,7 @@
 
         final int baseAlpha = Color.alpha(baseColor);
         final int alpha = MathUtils.constrain((int) (baseAlpha * alphaMod + 0.5f), 0, 255);
-        final int color = (baseColor & 0xFFFFFF) | (alpha << 24);
-        return color;
+        return (baseColor & 0xFFFFFF) | (alpha << 24);
     }
 
     /**
@@ -534,14 +578,18 @@
     }
 
     /**
-     * @return A factory that can create new instances of this ColorStateList.
+     * @return a factory that can create new instances of this ColorStateList
+     * @hide only for resource preloading
      */
-    ColorStateListFactory getFactory() {
-        return new ColorStateListFactory(this);
+    public ConstantState<ColorStateList> getConstantState() {
+        if (mFactory != null) {
+            mFactory = new ColorStateListFactory(this);
+        }
+        return mFactory;
     }
 
-    static class ColorStateListFactory extends ConstantState<ColorStateList> {
-        final ColorStateList mSrc;
+    private static class ColorStateListFactory extends ConstantState<ColorStateList> {
+        private final ColorStateList mSrc;
 
         public ColorStateListFactory(ColorStateList src) {
             mSrc = src;
@@ -559,13 +607,7 @@
 
         @Override
         public ColorStateList newInstance(Resources res, Theme theme) {
-            if (theme == null || !mSrc.canApplyTheme()) {
-                return mSrc;
-            }
-
-            final ColorStateList clone = new ColorStateList(mSrc);
-            clone.applyTheme(theme);
-            return clone;
+            return mSrc.obtainForTheme(theme);
         }
     }
 
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index b5eeb30..bc6d4ce 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -1284,14 +1284,12 @@
 
     /**
      * Set the locale. This is the preferred way for setting up the locale (instead of using the
-     * direct accessor). This will also set the userLocale and layout direction according to
-     * the locale.
+     * direct accessor). This will also set the layout direction according to the locale.
      *
      * @param loc The locale. Can be null.
      */
     public void setLocale(Locale loc) {
         locale = loc;
-        userSetLocale = true;
         setLayoutDirection(locale);
     }
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 44018ff..334d180 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,7 +16,10 @@
 
 package android.content.res;
 
+import android.annotation.AttrRes;
 import android.annotation.ColorInt;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -41,7 +44,6 @@
 import android.annotation.StringRes;
 import android.annotation.XmlRes;
 import android.content.pm.ActivityInfo;
-import android.content.res.ColorStateList.ColorStateListFactory;
 import android.graphics.Movie;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -112,8 +114,11 @@
     private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
     private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
             = new LongSparseArray<>();
-    private static final LongSparseArray<ColorStateListFactory> sPreloadedColorStateLists
-            = new LongSparseArray<>();
+    private static final LongSparseArray<android.content.res.ConstantState<ColorStateList>>
+            sPreloadedColorStateLists = new LongSparseArray<>();
+
+    private static final String CACHE_NOT_THEMED = "";
+    private static final String CACHE_NULL_THEME = "null_theme";
 
     // Pool of TypedArrays targeted to this Resources object.
     final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
@@ -1473,7 +1478,7 @@
          * @see #obtainStyledAttributes(int, int[])
          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
          */
-        public TypedArray obtainStyledAttributes(int[] attrs) {
+        public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
             final int len = attrs.length;
             final TypedArray array = TypedArray.obtain(Resources.this, len);
             array.mTheme = this;
@@ -1501,7 +1506,8 @@
          * @see #obtainStyledAttributes(int[])
          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
          */
-        public TypedArray obtainStyledAttributes(int resid, int[] attrs) throws NotFoundException {
+        public TypedArray obtainStyledAttributes(@StyleRes int resid, @StyleableRes int[] attrs)
+                throws NotFoundException {
             final int len = attrs.length;
             final TypedArray array = TypedArray.obtain(Resources.this, len);
             array.mTheme = this;
@@ -1584,7 +1590,7 @@
          * @see #obtainStyledAttributes(int, int[])
          */
         public TypedArray obtainStyledAttributes(AttributeSet set,
-                int[] attrs, int defStyleAttr, int defStyleRes) {
+                @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
             final int len = attrs.length;
             final TypedArray array = TypedArray.obtain(Resources.this, len);
 
@@ -2438,8 +2444,8 @@
             }
         }
 
-        // Next, check preloaded drawables. These are unthemed but may have
-        // themeable attributes.
+        // Next, check preloaded drawables. These may contain unresolved theme
+        // attributes.
         final ConstantState cs;
         if (isColorDrawable) {
             cs = sPreloadedColorDrawables.get(key);
@@ -2447,42 +2453,49 @@
             cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
         }
 
-        final Drawable dr;
+        Drawable dr;
         if (cs != null) {
-            final Drawable clonedDr = cs.newDrawable(this);
-            if (theme != null) {
-                dr = clonedDr.mutate();
-                dr.applyTheme(theme);
-                dr.clearMutated();
-            } else {
-                dr = clonedDr;
-            }
+            dr = cs.newDrawable(this);
         } else if (isColorDrawable) {
             dr = new ColorDrawable(value.data);
         } else {
-            dr = loadDrawableForCookie(value, id, theme);
+            dr = loadDrawableForCookie(value, id, null);
+        }
+
+        // Determine if the drawable has unresolved theme attributes. If it
+        // does, we'll need to apply a theme and store it in a theme-specific
+        // cache.
+        final String cacheKey;
+        if (!dr.canApplyTheme()) {
+            cacheKey = CACHE_NOT_THEMED;
+        } else if (theme == null) {
+            cacheKey = CACHE_NULL_THEME;
+        } else {
+            cacheKey = theme.getKey();
+            dr = dr.mutate();
+            dr.applyTheme(theme);
+            dr.clearMutated();
         }
 
         // If we were able to obtain a drawable, store it in the appropriate
-        // cache (either preload or themed).
+        // cache: preload, not themed, null theme, or theme-specific.
         if (dr != null) {
             dr.setChangingConfigurations(value.changingConfigurations);
-            cacheDrawable(value, theme, isColorDrawable, caches, key, dr);
+            cacheDrawable(value, isColorDrawable, caches, cacheKey, key, dr);
         }
 
         return dr;
     }
 
-    private void cacheDrawable(TypedValue value, Theme theme, boolean isColorDrawable,
+    private void cacheDrawable(TypedValue value, boolean isColorDrawable,
             ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
-            long key, Drawable dr) {
+            String cacheKey, long key, Drawable dr) {
         final ConstantState cs = dr.getConstantState();
         if (cs == null) {
             return;
         }
 
         if (mPreloading) {
-            // Preloaded drawables never have a theme, but may be themeable.
             final int changingConfigs = cs.getChangingConfigurations();
             if (isColorDrawable) {
                 if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
@@ -2504,14 +2517,13 @@
             }
         } else {
             synchronized (mAccessLock) {
-                final String themeKey = theme == null ? "" : theme.mKey;
-                LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
+                LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(cacheKey);
                 if (themedCache == null) {
                     // Clean out the caches before we add more. This shouldn't
                     // happen very often.
                     pruneCaches(caches);
                     themedCache = new LongSparseArray<>(1);
-                    caches.put(themeKey, themedCache);
+                    caches.put(cacheKey, themedCache);
                 }
                 themedCache.put(key, new WeakReference<>(cs));
             }
@@ -2609,42 +2621,43 @@
             ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
             long key, Theme theme) {
         synchronized (mAccessLock) {
-            final String themeKey = theme != null ? theme.mKey : "";
-            final LongSparseArray<WeakReference<ConstantState>> themedCache = caches.get(themeKey);
-            if (themedCache != null) {
-                final Drawable themedDrawable = getCachedDrawableLocked(themedCache, key);
-                if (themedDrawable != null) {
-                    return themedDrawable;
-                }
+            // First search theme-agnostic cache.
+            final Drawable unthemedDrawable = getCachedDrawableLocked(
+                    caches, key, CACHE_NOT_THEMED);
+            if (unthemedDrawable != null) {
+                return unthemedDrawable;
             }
 
-            // No cached drawable, we'll need to create a new one.
-            return null;
+            // Next search theme-specific cache.
+            final String themeKey = theme != null ? theme.getKey() : CACHE_NULL_THEME;
+            return getCachedDrawableLocked(caches, key, themeKey);
         }
     }
 
-    private ConstantState getConstantStateLocked(
-            LongSparseArray<WeakReference<ConstantState>> drawableCache, long key) {
-        final WeakReference<ConstantState> wr = drawableCache.get(key);
-        if (wr != null) {   // we have the key
-            final ConstantState entry = wr.get();
+    private Drawable getCachedDrawableLocked(
+            ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches,
+            long key, String themeKey) {
+        final LongSparseArray<WeakReference<ConstantState>> cache = caches.get(themeKey);
+        if (cache != null) {
+            final ConstantState entry = getConstantStateLocked(cache, key);
             if (entry != null) {
-                //Log.i(TAG, "Returning cached drawable @ #" +
-                //        Integer.toHexString(((Integer)key).intValue())
-                //        + " in " + this + ": " + entry);
-                return entry;
-            } else {  // our entry has been purged
-                drawableCache.delete(key);
+                return entry.newDrawable(this);
             }
         }
         return null;
     }
 
-    private Drawable getCachedDrawableLocked(
+    private ConstantState getConstantStateLocked(
             LongSparseArray<WeakReference<ConstantState>> drawableCache, long key) {
-        final ConstantState entry = getConstantStateLocked(drawableCache, key);
-        if (entry != null) {
-            return entry.newDrawable(this);
+        final WeakReference<ConstantState> wr = drawableCache.get(key);
+        if (wr != null) {
+            final ConstantState entry = wr.get();
+            if (entry != null) {
+                return entry;
+            } else {
+                // Our entry has been purged.
+                drawableCache.delete(key);
+            }
         }
         return null;
     }
@@ -2667,7 +2680,8 @@
         // Handle inline color definitions.
         if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
                 && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
+            final android.content.res.ConstantState<ColorStateList> factory =
+                    sPreloadedColorStateLists.get(key);
             if (factory != null) {
                 return factory.newInstance();
             }
@@ -2677,7 +2691,7 @@
             if (mPreloading) {
                 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                         "color")) {
-                    sPreloadedColorStateLists.put(key, csl.getFactory());
+                    sPreloadedColorStateLists.put(key, csl.getConstantState());
                 }
             }
 
@@ -2691,7 +2705,8 @@
             return csl;
         }
 
-        final ColorStateListFactory factory = sPreloadedColorStateLists.get(key);
+        final android.content.res.ConstantState<ColorStateList> factory =
+                sPreloadedColorStateLists.get(key);
         if (factory != null) {
             csl = factory.newInstance(this, theme);
         }
@@ -2704,10 +2719,10 @@
             if (mPreloading) {
                 if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
                         "color")) {
-                    sPreloadedColorStateLists.put(key, csl.getFactory());
+                    sPreloadedColorStateLists.put(key, csl.getConstantState());
                 }
             } else {
-                cache.put(key, theme, csl.getFactory());
+                cache.put(key, theme, csl.getConstantState());
             }
         }
 
diff --git a/core/java/android/database/AbstractCursor.java b/core/java/android/database/AbstractCursor.java
index b5b89dd..581fe7f 100644
--- a/core/java/android/database/AbstractCursor.java
+++ b/core/java/android/database/AbstractCursor.java
@@ -35,34 +35,38 @@
     private static final String TAG = "Cursor";
 
     /**
-     * @deprecated This is never updated by this class and should not be used
+     * @removed This field should not be used.
      */
-    @Deprecated
     protected HashMap<Long, Map<String, Object>> mUpdatedRows;
 
-    protected int mPos;
-
     /**
-     * This must be set to the index of the row ID column by any
-     * subclass that wishes to support updates.
-     *
-     * @deprecated This field should not be used.
+     * @removed This field should not be used.
      */
-    @Deprecated
     protected int mRowIdColumnIndex;
 
     /**
-     * If {@link #mRowIdColumnIndex} is not -1 this contains contains the value of
-     * the column at {@link #mRowIdColumnIndex} for the current row this cursor is
-     * pointing at.
-     *
-     * @deprecated This field should not be used.
+     * @removed This field should not be used.
      */
-    @Deprecated
     protected Long mCurrentRowID;
 
+    /**
+     * @deprecated Use {@link #getPosition()} instead.
+     */
+    @Deprecated
+    protected int mPos;
+
+    /**
+     * @deprecated Use {@link #isClosed()} instead.
+     */
+    @Deprecated
     protected boolean mClosed;
+
+    /**
+     * @deprecated Do not use.
+     */
+    @Deprecated
     protected ContentResolver mContentResolver;
+
     private Uri mNotifyUri;
 
     private final Object mSelfObserverLock = new Object();
@@ -76,18 +80,28 @@
 
     /* -------------------------------------------------------- */
     /* These need to be implemented by subclasses */
+    @Override
     abstract public int getCount();
 
+    @Override
     abstract public String[] getColumnNames();
 
+    @Override
     abstract public String getString(int column);
+    @Override
     abstract public short getShort(int column);
+    @Override
     abstract public int getInt(int column);
+    @Override
     abstract public long getLong(int column);
+    @Override
     abstract public float getFloat(int column);
+    @Override
     abstract public double getDouble(int column);
+    @Override
     abstract public boolean isNull(int column);
 
+    @Override
     public int getType(int column) {
         // Reflects the assumption that all commonly used field types (meaning everything
         // but blobs) are convertible to strings so it should be safe to call
@@ -96,6 +110,7 @@
     }
 
     // TODO implement getBlob in all cursor types
+    @Override
     public byte[] getBlob(int column) {
         throw new UnsupportedOperationException("getBlob is not supported");
     }
@@ -108,14 +123,17 @@
      *
      * @return The pre-filled window that backs this cursor, or null if none.
      */
+    @Override
     public CursorWindow getWindow() {
         return null;
     }
 
+    @Override
     public int getColumnCount() {
         return getColumnNames().length;
     }
 
+    @Override
     public void deactivate() {
         onDeactivateOrClose();
     }
@@ -129,6 +147,7 @@
         mDataSetObservable.notifyInvalidated();
     }
 
+    @Override
     public boolean requery() {
         if (mSelfObserver != null && mSelfObserverRegistered == false) {
             mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
@@ -138,10 +157,12 @@
         return true;
     }
 
+    @Override
     public boolean isClosed() {
         return mClosed;
     }
 
+    @Override
     public void close() {
         mClosed = true;
         mContentObservable.unregisterAll();
@@ -158,11 +179,13 @@
      * @param newPosition the position that we're moving to
      * @return true if the move is successful, false otherwise
      */
+    @Override
     public boolean onMove(int oldPosition, int newPosition) {
         return true;
     }
 
 
+    @Override
     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
         // Default implementation, uses getString
         String result = getString(columnIndex);
@@ -183,15 +206,14 @@
     /* Implementation */
     public AbstractCursor() {
         mPos = -1;
-        mRowIdColumnIndex = -1;
-        mCurrentRowID = null;
-        mUpdatedRows = new HashMap<Long, Map<String, Object>>();
     }
 
+    @Override
     public final int getPosition() {
         return mPos;
     }
 
+    @Override
     public final boolean moveToPosition(int position) {
         // Make sure position isn't past the end of the cursor
         final int count = getCount();
@@ -216,9 +238,6 @@
             mPos = -1;
         } else {
             mPos = position;
-            if (mRowIdColumnIndex != -1) {
-                mCurrentRowID = Long.valueOf(getLong(mRowIdColumnIndex));
-            }
         }
 
         return result;
@@ -229,35 +248,43 @@
         DatabaseUtils.cursorFillWindow(this, position, window);
     }
 
+    @Override
     public final boolean move(int offset) {
         return moveToPosition(mPos + offset);
     }
 
+    @Override
     public final boolean moveToFirst() {
         return moveToPosition(0);
     }
 
+    @Override
     public final boolean moveToLast() {
         return moveToPosition(getCount() - 1);
     }
 
+    @Override
     public final boolean moveToNext() {
         return moveToPosition(mPos + 1);
     }
 
+    @Override
     public final boolean moveToPrevious() {
         return moveToPosition(mPos - 1);
     }
 
+    @Override
     public final boolean isFirst() {
         return mPos == 0 && getCount() != 0;
     }
 
+    @Override
     public final boolean isLast() {
         int cnt = getCount();
         return mPos == (cnt - 1) && cnt != 0;
     }
 
+    @Override
     public final boolean isBeforeFirst() {
         if (getCount() == 0) {
             return true;
@@ -265,6 +292,7 @@
         return mPos == -1;
     }
 
+    @Override
     public final boolean isAfterLast() {
         if (getCount() == 0) {
             return true;
@@ -272,6 +300,7 @@
         return mPos == getCount();
     }
 
+    @Override
     public int getColumnIndex(String columnName) {
         // Hack according to bug 903852
         final int periodIndex = columnName.lastIndexOf('.');
@@ -297,6 +326,7 @@
         return -1;
     }
 
+    @Override
     public int getColumnIndexOrThrow(String columnName) {
         final int index = getColumnIndex(columnName);
         if (index < 0) {
@@ -305,14 +335,17 @@
         return index;
     }
 
+    @Override
     public String getColumnName(int columnIndex) {
         return getColumnNames()[columnIndex];
     }
 
+    @Override
     public void registerContentObserver(ContentObserver observer) {
         mContentObservable.registerObserver(observer);
     }
 
+    @Override
     public void unregisterContentObserver(ContentObserver observer) {
         // cursor will unregister all observers when it close
         if (!mClosed) {
@@ -320,10 +353,12 @@
         }
     }
 
+    @Override
     public void registerDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.registerObserver(observer);
     }
 
+    @Override
     public void unregisterDataSetObserver(DataSetObserver observer) {
         mDataSetObservable.unregisterObserver(observer);
     }
@@ -350,6 +385,7 @@
      * @param notifyUri The URI to watch for changes. This can be a
      * specific row URI, or a base URI for a whole class of content.
      */
+    @Override
     public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
         setNotificationUri(cr, notifyUri, UserHandle.myUserId());
     }
@@ -368,31 +404,29 @@
         }
     }
 
+    @Override
     public Uri getNotificationUri() {
         synchronized (mSelfObserverLock) {
             return mNotifyUri;
         }
     }
 
+    @Override
     public boolean getWantsAllOnMoveCalls() {
         return false;
     }
 
-    /**
-     * Sets a {@link Bundle} that will be returned by {@link #getExtras()}.  <code>null</code> will
-     * be converted into {@link Bundle#EMPTY}.
-     *
-     * @param extras {@link Bundle} to set.
-     * @hide
-     */
+    @Override
     public void setExtras(Bundle extras) {
         mExtras = (extras == null) ? Bundle.EMPTY : extras;
     }
 
+    @Override
     public Bundle getExtras() {
         return mExtras;
     }
 
+    @Override
     public Bundle respond(Bundle extras) {
         return Bundle.EMPTY;
     }
diff --git a/core/java/android/database/BulkCursorToCursorAdaptor.java b/core/java/android/database/BulkCursorToCursorAdaptor.java
index 98c7043..8576715 100644
--- a/core/java/android/database/BulkCursorToCursorAdaptor.java
+++ b/core/java/android/database/BulkCursorToCursorAdaptor.java
@@ -41,7 +41,6 @@
     public void initialize(BulkCursorDescriptor d) {
         mBulkCursor = d.cursor;
         mColumns = d.columnNames;
-        mRowIdColumnIndex = DatabaseUtils.findRowIdColumnIndex(mColumns);
         mWantsAllOnMoveCalls = d.wantsAllOnMoveCalls;
         mCount = d.count;
         if (d.window != null) {
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index fc2a885..d10c9b8 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -444,6 +444,13 @@
     boolean getWantsAllOnMoveCalls();
 
     /**
+     * Sets a {@link Bundle} that will be returned by {@link #getExtras()}.
+     *
+     * @param extras {@link Bundle} to set, or null to set an empty bundle.
+     */
+    void setExtras(Bundle extras);
+
+    /**
      * Returns a bundle of extra values. This is an optional way for cursors to provide out-of-band
      * metadata to their users. One use of this is for reporting on the progress of network requests
      * that are required to fetch data for the cursor.
diff --git a/core/java/android/database/CursorWrapper.java b/core/java/android/database/CursorWrapper.java
index d8fcb17..63a2792 100644
--- a/core/java/android/database/CursorWrapper.java
+++ b/core/java/android/database/CursorWrapper.java
@@ -45,163 +45,210 @@
         return mCursor;
     }
 
+    @Override
     public void close() {
         mCursor.close(); 
     }
  
+    @Override
     public boolean isClosed() {
         return mCursor.isClosed();
     }
 
+    @Override
     public int getCount() {
         return mCursor.getCount();
     }
 
+    @Override
+    @Deprecated
     public void deactivate() {
         mCursor.deactivate();
     }
 
+    @Override
     public boolean moveToFirst() {
         return mCursor.moveToFirst();
     }
 
+    @Override
     public int getColumnCount() {
         return mCursor.getColumnCount();
     }
 
+    @Override
     public int getColumnIndex(String columnName) {
         return mCursor.getColumnIndex(columnName);
     }
 
+    @Override
     public int getColumnIndexOrThrow(String columnName)
             throws IllegalArgumentException {
         return mCursor.getColumnIndexOrThrow(columnName);
     }
 
+    @Override
     public String getColumnName(int columnIndex) {
          return mCursor.getColumnName(columnIndex);
     }
 
+    @Override
     public String[] getColumnNames() {
         return mCursor.getColumnNames();
     }
 
+    @Override
     public double getDouble(int columnIndex) {
         return mCursor.getDouble(columnIndex);
     }
 
+    @Override
+    public void setExtras(Bundle extras) {
+        mCursor.setExtras(extras);
+    }
+
+    @Override
     public Bundle getExtras() {
         return mCursor.getExtras();
     }
 
+    @Override
     public float getFloat(int columnIndex) {
         return mCursor.getFloat(columnIndex);
     }
 
+    @Override
     public int getInt(int columnIndex) {
         return mCursor.getInt(columnIndex);
     }
 
+    @Override
     public long getLong(int columnIndex) {
         return mCursor.getLong(columnIndex);
     }
 
+    @Override
     public short getShort(int columnIndex) {
         return mCursor.getShort(columnIndex);
     }
 
+    @Override
     public String getString(int columnIndex) {
         return mCursor.getString(columnIndex);
     }
     
+    @Override
     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
         mCursor.copyStringToBuffer(columnIndex, buffer);
     }
 
+    @Override
     public byte[] getBlob(int columnIndex) {
         return mCursor.getBlob(columnIndex);
     }
     
+    @Override
     public boolean getWantsAllOnMoveCalls() {
         return mCursor.getWantsAllOnMoveCalls();
     }
 
+    @Override
     public boolean isAfterLast() {
         return mCursor.isAfterLast();
     }
 
+    @Override
     public boolean isBeforeFirst() {
         return mCursor.isBeforeFirst();
     }
 
+    @Override
     public boolean isFirst() {
         return mCursor.isFirst();
     }
 
+    @Override
     public boolean isLast() {
         return mCursor.isLast();
     }
 
+    @Override
     public int getType(int columnIndex) {
         return mCursor.getType(columnIndex);
     }
 
+    @Override
     public boolean isNull(int columnIndex) {
         return mCursor.isNull(columnIndex);
     }
 
+    @Override
     public boolean moveToLast() {
         return mCursor.moveToLast();
     }
 
+    @Override
     public boolean move(int offset) {
         return mCursor.move(offset);
     }
 
+    @Override
     public boolean moveToPosition(int position) {
         return mCursor.moveToPosition(position);
     }
 
+    @Override
     public boolean moveToNext() {
         return mCursor.moveToNext();
     }
 
+    @Override
     public int getPosition() {
         return mCursor.getPosition();
     }
 
+    @Override
     public boolean moveToPrevious() {
         return mCursor.moveToPrevious();
     }
 
+    @Override
     public void registerContentObserver(ContentObserver observer) {
-        mCursor.registerContentObserver(observer);   
+        mCursor.registerContentObserver(observer);
     }
 
+    @Override
     public void registerDataSetObserver(DataSetObserver observer) {
-        mCursor.registerDataSetObserver(observer);   
+        mCursor.registerDataSetObserver(observer);
     }
 
+    @Override
+    @Deprecated
     public boolean requery() {
         return mCursor.requery();
     }
 
+    @Override
     public Bundle respond(Bundle extras) {
         return mCursor.respond(extras);
     }
 
+    @Override
     public void setNotificationUri(ContentResolver cr, Uri uri) {
-        mCursor.setNotificationUri(cr, uri);        
+        mCursor.setNotificationUri(cr, uri);
     }
 
+    @Override
     public Uri getNotificationUri() {
         return mCursor.getNotificationUri();
     }
 
+    @Override
     public void unregisterContentObserver(ContentObserver observer) {
-        mCursor.unregisterContentObserver(observer);        
+        mCursor.unregisterContentObserver(observer);
     }
 
+    @Override
     public void unregisterDataSetObserver(DataSetObserver observer) {
         mCursor.unregisterDataSetObserver(observer);
     }
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 5a1a8e2..2dc5ca4 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -105,7 +105,6 @@
         mQuery = query;
 
         mColumns = query.getColumnNames();
-        mRowIdColumnIndex = DatabaseUtils.findRowIdColumnIndex(mColumns);
     }
 
     /**
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
index d5dfaf6..9bc2f46 100644
--- a/core/java/android/hardware/ICameraService.aidl
+++ b/core/java/android/hardware/ICameraService.aidl
@@ -75,4 +75,11 @@
                     out BinderHolder device);
 
     int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
+
+    /**
+     * Notify the camera service of a system event.  Should only be called from system_server.
+     *
+     * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
+     */
+    oneway void notifySystemEvent(int eventId, int arg0);
 }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1503bf5..f01c540 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -939,6 +939,129 @@
             new Key<Integer>("android.lens.facing", int.class);
 
     /**
+     * <p>The orientation of the camera relative to the sensor
+     * coordinate system.</p>
+     * <p>The four coefficients that describe the quarternion
+     * rotation from the Android sensor coordinate system to a
+     * camera-aligned coordinate system where the X-axis is
+     * aligned with the long side of the image sensor, the Y-axis
+     * is aligned with the short side of the image sensor, and
+     * the Z-axis is aligned with the optical axis of the sensor.</p>
+     * <p>To convert from the quarternion coefficients <code>(x,y,z,w)</code>
+     * to the axis of rotation <code>(a_x, a_y, a_z)</code> and rotation
+     * amount <code>theta</code>, the following formulas can be used:</p>
+     * <pre><code> theta = 2 * acos(w)
+     * a_x = x / sin(theta/2)
+     * a_y = y / sin(theta/2)
+     * a_z = z / sin(theta/2)
+     * </code></pre>
+     * <p>To create a 3x3 rotation matrix that applies the rotation
+     * defined by this quarternion, the following matrix can be
+     * used:</p>
+     * <pre><code>R = [ 1 - 2y^2 - 2z^2,       2xy - 2zw,       2xz + 2yw,
+     *            2xy + 2zw, 1 - 2x^2 - 2z^2,       2yz - 2xw,
+     *            2xz - 2yw,       2yz + 2xw, 1 - 2x^2 - 2y^2 ]
+     * </code></pre>
+     * <p>This matrix can then be used to apply the rotation to a
+     *  column vector point with</p>
+     * <p><code>p' = Rp</code></p>
+     * <p>where <code>p</code> is in the device sensor coordinate system, and
+     *  <code>p'</code> is in the camera-oriented coordinate system.</p>
+     * <p><b>Units</b>:
+     * Quarternion coefficients</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_POSE_ROTATION =
+            new Key<float[]>("android.lens.poseRotation", float[].class);
+
+    /**
+     * <p>Position of the camera optical center.</p>
+     * <p>As measured in the device sensor coordinate system, the
+     * position of the camera device's optical center, as a
+     * three-dimensional vector <code>(x,y,z)</code>.</p>
+     * <p>To transform a world position to a camera-device centered
+     * coordinate system, the position must be translated by this
+     * vector and then rotated by {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p>
+     * <p><b>Units</b>: Meters</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_POSE_TRANSLATION =
+            new Key<float[]>("android.lens.poseTranslation", float[].class);
+
+    /**
+     * <p>The parameters for this camera device's intrinsic
+     * calibration.</p>
+     * <p>The five calibration parameters that describe the
+     * transform from camera-centric 3D coordinates to sensor
+     * pixel coordinates:</p>
+     * <pre><code>[f_x, f_y, c_x, c_y, s]
+     * </code></pre>
+     * <p>Where <code>f_x</code> and <code>f_y</code> are the horizontal and vertical
+     * focal lengths, <code>[c_x, c_y]</code> is the position of the optical
+     * axis, and <code>s</code> is a skew parameter for the sensor plane not
+     * being aligned with the lens plane.</p>
+     * <p>These are typically used within a transformation matrix K:</p>
+     * <pre><code>K = [ f_x,   s, c_x,
+     *        0, f_y, c_y,
+     *        0    0,   1 ]
+     * </code></pre>
+     * <p>which can then be combined with the camera pose rotation
+     * <code>R</code> and translation <code>t</code> ({@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} and
+     * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, respective) to calculate the
+     * complete transform from world coordinates to pixel
+     * coordinates:</p>
+     * <pre><code>P = [ K 0   * [ R t
+     *      0 1 ]     0 1 ]
+     * </code></pre>
+     * <p>and with <code>p_w</code> being a point in the world coordinate system
+     * and <code>p_s</code> being a point in the camera active pixel array
+     * coordinate system, and with the mapping including the
+     * homogeneous division by z:</p>
+     * <pre><code> p_h = (x_h, y_h, z_h) = P p_w
+     * p_s = p_h / z_h
+     * </code></pre>
+     * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world
+     * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
+     * (depth) in pixel coordinates.</p>
+     * <p><b>Units</b>:
+     * Pixels in the android.sensor.activeArraySize coordinate
+     * system.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
+            new Key<float[]>("android.lens.intrinsicCalibration", float[].class);
+
+    /**
+     * <p>The correction coefficients to correct for this camera device's
+     * radial lens distortion.</p>
+     * <p>Three cofficients <code>[kappa_1, kappa_2, kappa_3]</code> that
+     * can be used to correct the lens's radial geometric
+     * distortion with the mapping equations:</p>
+     * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 )
+     * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 )
+     * </code></pre>
+     * <p>where <code>[x_i, y_i]</code> are normalized coordinates with <code>(0,0)</code>
+     * at the lens optical center, and <code>[-1, 1]</code> are the edges of
+     * the active pixel array; and where <code>[x_c, y_c]</code> are the
+     * corrected normalized coordinates with radial distortion
+     * removed; and <code>r^2 = x_i^2 + y_i^2</code>.</p>
+     * <p><b>Units</b>:
+     * Coefficients for a 6th-degree even radial polynomial.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_RADIAL_DISTORTION =
+            new Key<float[]>("android.lens.radialDistortion", float[].class);
+
+    /**
      * <p>List of noise reduction modes for {@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode} that are supported
      * by this camera device.</p>
      * <p>Full-capability camera devices will always support OFF and FAST.</p>
@@ -1107,8 +1230,7 @@
      * that can be configured and used simultaneously by a camera device.</p>
      * <p>When set to 0, it means no input stream is supported.</p>
      * <p>The image format for a input stream can be any supported
-     * format provided by
-     * android.scaler.availableInputOutputFormatsMap. When using an
+     * format returned by StreamConfigurationMap#getInputFormats. When using an
      * input stream, there must be at least one output stream
      * configured to to receive the reprocessed images.</p>
      * <p>When an input stream and some output streams are used in a reprocessing request,
@@ -1408,12 +1530,12 @@
      * </thead>
      * <tbody>
      * <tr>
-     * <td align="left">OPAQUE</td>
+     * <td align="left">PRIVATE (ImageFormat#PRIVATE)</td>
      * <td align="left">JPEG</td>
      * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
      * <tr>
-     * <td align="left">OPAQUE</td>
+     * <td align="left">PRIVATE</td>
      * <td align="left">YUV_420_888</td>
      * <td align="left">OPAQUE_REPROCESSING</td>
      * </tr>
@@ -1429,25 +1551,23 @@
      * </tr>
      * </tbody>
      * </table>
-     * <p>OPAQUE refers to a device-internal format that is not directly application-visible.
-     * An OPAQUE input or output surface can be acquired by
-     * OpaqueImageRingBufferQueue#getInputSurface() or
-     * OpaqueImageRingBufferQueue#getOutputSurface().
-     * For a OPAQUE_REPROCESSING-capable camera device, using the OPAQUE format
+     * <p>PRIVATE refers to a device-internal format that is not directly application-visible.
+     * A PRIVATE input surface can be acquired by
+     * ImageReader.newOpaqueInstance(width, height, maxImages).
+     * For a OPAQUE_REPROCESSING-capable camera device, using the PRIVATE format
      * as either input or output will never hurt maximum frame rate (i.e.
-     * StreamConfigurationMap#getOutputStallDuration(klass,Size) is always 0),
-     * where klass is android.media.OpaqueImageRingBufferQueue.class.</p>
+     * StreamConfigurationMap#getOutputStallDuration(format, size) is always 0),
+     * where format is ImageFormat#PRIVATE.</p>
      * <p>Attempting to configure an input stream with output streams not
      * listed as available in this map is not valid.</p>
-     * <p>TODO: typedef to ReprocessFormatMap</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      * @see CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS
      * @hide
      */
-    public static final Key<int[]> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
-            new Key<int[]>("android.scaler.availableInputOutputFormatsMap", int[].class);
+    public static final Key<android.hardware.camera2.params.ReprocessFormatsMap> SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP =
+            new Key<android.hardware.camera2.params.ReprocessFormatsMap>("android.scaler.availableInputOutputFormatsMap", android.hardware.camera2.params.ReprocessFormatsMap.class);
 
     /**
      * <p>The available stream configurations that this
@@ -2354,8 +2474,8 @@
      * <p>Camera devices that support the MANUAL_POST_PROCESSING capability will always contain
      * at least one of below mode combinations:</p>
      * <ul>
-     * <li>CONTRAST_CURVE and FAST</li>
-     * <li>GAMMA_VALUE, PRESET_CURVE, and FAST</li>
+     * <li>CONTRAST_CURVE, FAST and HIGH_QUALITY</li>
+     * <li>GAMMA_VALUE, PRESET_CURVE, FAST and HIGH_QUALITY</li>
      * </ul>
      * <p>This includes all FULL level devices.</p>
      * <p><b>Range of valid values:</b><br>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 7f901c8..2192ab7 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -448,17 +448,18 @@
      * <p>The camera device supports the Zero Shutter Lag reprocessing use case.</p>
      * <ul>
      * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
-     * <li>OPAQUE is supported as an output/input format, that is,
-     *   StreamConfigurationMap#getOutputSizes(klass) and
-     *   StreamConfigurationMap#getInputSizes(klass) return non empty Size[] and have common
-     *   sizes, where klass is android.media.OpaqueImageRingBufferQueue.class. See
-     *   android.scaler.availableInputOutputFormatsMap for detailed information about
-     *   OPAQUE format.</li>
-     * <li>android.scaler.availableInputOutputFormatsMap has the required map entries.</li>
-     * <li>Using OPAQUE does not cause a frame rate drop
+     * <li>ImageFormat#PRIVATE is supported as an output/input format, that is,
+     *   ImageFormat#PRIVATE is included in the lists of formats returned by
+     *   StreamConfigurationMap#getInputFormats and
+     *   StreamConfigurationMap#getOutputFormats.</li>
+     * <li>StreamConfigurationMap#getValidOutputFormatsForInput returns non empty int[] for
+     *   each supported input format returned by StreamConfigurationMap#getInputFormats.</li>
+     * <li>Each size returned by StreamConfigurationMap#getInputSizes(ImageFormat#PRIVATE)
+     *   is also included in StreamConfigurationMap#getOutputSizes(ImageFormat#PRIVATE)</li>
+     * <li>Using ImageFormat#PRIVATE does not cause a frame rate drop
      *   relative to the sensor's maximum capture rate (at that
-     *   resolution), see android.scaler.availableInputOutputFormatsMap for more details.</li>
-     * <li>OPAQUE will be reprocessable into both YUV_420_888
+     *   resolution).</li>
+     * <li>ImageFormat#PRIVATE will be reprocessable into both YUV_420_888
      *   and JPEG formats.</li>
      * <li>The maximum available resolution for OPAQUE streams
      *   (both input/output) will match the maximum available
@@ -539,27 +540,29 @@
     public static final int REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE = 6;
 
     /**
-     * <p>The camera device supports the YUV420_888 reprocessing use case, similar as
+     * <p>The camera device supports the YUV_420_888 reprocessing use case, similar as
      * OPAQUE_REPROCESSING, This capability requires the camera device to support the
      * following:</p>
      * <ul>
      * <li>One input stream is supported, that is, <code>{@link CameraCharacteristics#REQUEST_MAX_NUM_INPUT_STREAMS android.request.maxNumInputStreams} == 1</code>.</li>
-     * <li>YUV420_888 is supported as a common format for both input and output, that is,
-     *   StreamConfigurationMap#getOutputSizes(YUV420_888) and
-     *   StreamConfigurationMap#getInputSizes(YUV420_888) return non empty Size[] and have
-     *   common sizes.</li>
-     * <li>android.scaler.availableInputOutputFormatsMap has the required map entries.</li>
-     * <li>Using YUV420_888 does not cause a frame rate drop
-     *   relative to the sensor's maximum capture rate (at that
-     *   resolution), see android.scaler.availableInputOutputFormatsMap for more details.</li>
-     * <li>YUV420_888 will be reprocessable into both YUV_420_888
+     * <li>YUV_420_888 is supported as an output/input format, that is,
+     *   YUV_420_888 is included in the lists of formats returned by
+     *   StreamConfigurationMap#getInputFormats and
+     *   StreamConfigurationMap#getOutputFormats.</li>
+     * <li>StreamConfigurationMap#getValidOutputFormatsForInput returns non empty int[] for
+     *   each supported input format returned by StreamConfigurationMap#getInputFormats.</li>
+     * <li>Each size returned by StreamConfigurationMap#getInputSizes(YUV_420_888)
+     *   is also included in StreamConfigurationMap#getOutputSizes(YUV_420_888)</li>
+     * <li>Using YUV_420_888 does not cause a frame rate drop
+     *   relative to the sensor's maximum capture rate (at that resolution).</li>
+     * <li>YUV_420_888 will be reprocessable into both YUV_420_888
      *   and JPEG formats.</li>
-     * <li>The maximum available resolution for YUV420_888 streams
+     * <li>The maximum available resolution for YUV_420_888 streams
      *   (both input/output) will match the maximum available
      *   resolution of JPEG streams.</li>
      * <li>Only the below controls are effective for reprocessing requests and will be
      *   present in capture results. The reprocess requests are from the original capture
-     *   results that are assocaited with the intermidate YUV420_888 output buffers.
+     *   results that are assocaited with the intermidate YUV_420_888 output buffers.
      *   All other controls in the reprocess requests will be ignored by the camera device.<ul>
      * <li>android.jpeg.*</li>
      * <li>{@link CaptureRequest#NOISE_REDUCTION_MODE android.noiseReduction.mode}</li>
@@ -852,8 +855,8 @@
 
     /**
      * <p>Color correction processing operates at improved
-     * quality but reduced capture rate (relative to sensor raw
-     * output).</p>
+     * quality but the capture rate might be reduced (relative to sensor
+     * raw output rate)</p>
      * <p>Advanced white balance adjustments above and beyond
      * the specified white balance pipeline may be applied.</p>
      * <p>If AWB is enabled with <code>{@link CaptureRequest#CONTROL_AWB_MODE android.control.awbMode} != OFF</code>, then
@@ -883,8 +886,8 @@
     public static final int COLOR_CORRECTION_ABERRATION_MODE_FAST = 1;
 
     /**
-     * <p>Aberration correction operates at improved quality but reduced
-     * capture rate (relative to sensor raw output).</p>
+     * <p>Aberration correction operates at improved quality but the capture rate might be
+     * reduced (relative to sensor raw output rate)</p>
      * @see CaptureRequest#COLOR_CORRECTION_ABERRATION_MODE
      */
     public static final int COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY = 2;
@@ -1797,7 +1800,7 @@
     public static final int EDGE_MODE_FAST = 1;
 
     /**
-     * <p>Apply high-quality edge enhancement, at a cost of reducing output frame rate.</p>
+     * <p>Apply high-quality edge enhancement, at a cost of possibly reduced output frame rate.</p>
      * @see CaptureRequest#EDGE_MODE
      */
     public static final int EDGE_MODE_HIGH_QUALITY = 2;
@@ -1852,7 +1855,7 @@
 
     /**
      * <p>High-quality hot pixel correction is applied, at a cost
-     * of reducing frame rate relative to sensor raw output.</p>
+     * of possibly reduced frame rate relative to sensor raw output.</p>
      * <p>The hotpixel map may be returned in {@link CaptureResult#STATISTICS_HOT_PIXEL_MAP android.statistics.hotPixelMap}.</p>
      *
      * @see CaptureResult#STATISTICS_HOT_PIXEL_MAP
@@ -1894,8 +1897,8 @@
     public static final int NOISE_REDUCTION_MODE_FAST = 1;
 
     /**
-     * <p>High-quality noise reduction is applied, at the cost of reducing frame rate
-     * relative to sensor output.</p>
+     * <p>High-quality noise reduction is applied, at the cost of possibly reduced frame
+     * rate relative to sensor output.</p>
      * @see CaptureRequest#NOISE_REDUCTION_MODE
      */
     public static final int NOISE_REDUCTION_MODE_HIGH_QUALITY = 2;
@@ -2032,7 +2035,7 @@
 
     /**
      * <p>Apply high-quality lens shading correction, at the
-     * cost of reduced frame rate.</p>
+     * cost of possibly reduced frame rate.</p>
      * @see CaptureRequest#SHADING_MODE
      */
     public static final int SHADING_MODE_HIGH_QUALITY = 2;
@@ -2105,7 +2108,7 @@
 
     /**
      * <p>High-quality gamma mapping and color enhancement will be applied, at
-     * the cost of reduced frame rate compared to raw sensor output.</p>
+     * the cost of possibly reduced frame rate compared to raw sensor output.</p>
      * @see CaptureRequest#TONEMAP_MODE
      */
     public static final int TONEMAP_MODE_HIGH_QUALITY = 2;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index e346dc2..d8f92e5 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2532,6 +2532,129 @@
             new Key<Integer>("android.lens.state", int.class);
 
     /**
+     * <p>The orientation of the camera relative to the sensor
+     * coordinate system.</p>
+     * <p>The four coefficients that describe the quarternion
+     * rotation from the Android sensor coordinate system to a
+     * camera-aligned coordinate system where the X-axis is
+     * aligned with the long side of the image sensor, the Y-axis
+     * is aligned with the short side of the image sensor, and
+     * the Z-axis is aligned with the optical axis of the sensor.</p>
+     * <p>To convert from the quarternion coefficients <code>(x,y,z,w)</code>
+     * to the axis of rotation <code>(a_x, a_y, a_z)</code> and rotation
+     * amount <code>theta</code>, the following formulas can be used:</p>
+     * <pre><code> theta = 2 * acos(w)
+     * a_x = x / sin(theta/2)
+     * a_y = y / sin(theta/2)
+     * a_z = z / sin(theta/2)
+     * </code></pre>
+     * <p>To create a 3x3 rotation matrix that applies the rotation
+     * defined by this quarternion, the following matrix can be
+     * used:</p>
+     * <pre><code>R = [ 1 - 2y^2 - 2z^2,       2xy - 2zw,       2xz + 2yw,
+     *            2xy + 2zw, 1 - 2x^2 - 2z^2,       2yz - 2xw,
+     *            2xz - 2yw,       2yz + 2xw, 1 - 2x^2 - 2y^2 ]
+     * </code></pre>
+     * <p>This matrix can then be used to apply the rotation to a
+     *  column vector point with</p>
+     * <p><code>p' = Rp</code></p>
+     * <p>where <code>p</code> is in the device sensor coordinate system, and
+     *  <code>p'</code> is in the camera-oriented coordinate system.</p>
+     * <p><b>Units</b>:
+     * Quarternion coefficients</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_POSE_ROTATION =
+            new Key<float[]>("android.lens.poseRotation", float[].class);
+
+    /**
+     * <p>Position of the camera optical center.</p>
+     * <p>As measured in the device sensor coordinate system, the
+     * position of the camera device's optical center, as a
+     * three-dimensional vector <code>(x,y,z)</code>.</p>
+     * <p>To transform a world position to a camera-device centered
+     * coordinate system, the position must be translated by this
+     * vector and then rotated by {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p>
+     * <p><b>Units</b>: Meters</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_POSE_TRANSLATION =
+            new Key<float[]>("android.lens.poseTranslation", float[].class);
+
+    /**
+     * <p>The parameters for this camera device's intrinsic
+     * calibration.</p>
+     * <p>The five calibration parameters that describe the
+     * transform from camera-centric 3D coordinates to sensor
+     * pixel coordinates:</p>
+     * <pre><code>[f_x, f_y, c_x, c_y, s]
+     * </code></pre>
+     * <p>Where <code>f_x</code> and <code>f_y</code> are the horizontal and vertical
+     * focal lengths, <code>[c_x, c_y]</code> is the position of the optical
+     * axis, and <code>s</code> is a skew parameter for the sensor plane not
+     * being aligned with the lens plane.</p>
+     * <p>These are typically used within a transformation matrix K:</p>
+     * <pre><code>K = [ f_x,   s, c_x,
+     *        0, f_y, c_y,
+     *        0    0,   1 ]
+     * </code></pre>
+     * <p>which can then be combined with the camera pose rotation
+     * <code>R</code> and translation <code>t</code> ({@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} and
+     * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, respective) to calculate the
+     * complete transform from world coordinates to pixel
+     * coordinates:</p>
+     * <pre><code>P = [ K 0   * [ R t
+     *      0 1 ]     0 1 ]
+     * </code></pre>
+     * <p>and with <code>p_w</code> being a point in the world coordinate system
+     * and <code>p_s</code> being a point in the camera active pixel array
+     * coordinate system, and with the mapping including the
+     * homogeneous division by z:</p>
+     * <pre><code> p_h = (x_h, y_h, z_h) = P p_w
+     * p_s = p_h / z_h
+     * </code></pre>
+     * <p>so <code>[x_s, y_s]</code> is the pixel coordinates of the world
+     * point, <code>z_s = 1</code>, and <code>w_s</code> is a measurement of disparity
+     * (depth) in pixel coordinates.</p>
+     * <p><b>Units</b>:
+     * Pixels in the android.sensor.activeArraySize coordinate
+     * system.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_INTRINSIC_CALIBRATION =
+            new Key<float[]>("android.lens.intrinsicCalibration", float[].class);
+
+    /**
+     * <p>The correction coefficients to correct for this camera device's
+     * radial lens distortion.</p>
+     * <p>Three cofficients <code>[kappa_1, kappa_2, kappa_3]</code> that
+     * can be used to correct the lens's radial geometric
+     * distortion with the mapping equations:</p>
+     * <pre><code> x_c = x_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 )
+     * y_c = y_i * ( 1 + kappa_1 * r^2 + kappa_2 * r^4 + kappa_3 * r^6 )
+     * </code></pre>
+     * <p>where <code>[x_i, y_i]</code> are normalized coordinates with <code>(0,0)</code>
+     * at the lens optical center, and <code>[-1, 1]</code> are the edges of
+     * the active pixel array; and where <code>[x_c, y_c]</code> are the
+     * corrected normalized coordinates with radial distortion
+     * removed; and <code>r^2 = x_i^2 + y_i^2</code>.</p>
+     * <p><b>Units</b>:
+     * Coefficients for a 6th-degree even radial polynomial.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     */
+    @PublicKey
+    public static final Key<float[]> LENS_RADIAL_DISTORTION =
+            new Key<float[]>("android.lens.radialDistortion", float[].class);
+
+    /**
      * <p>Mode of operation for the noise reduction algorithm.</p>
      * <p>The noise reduction algorithm attempts to improve image quality by removing
      * excessive noise added by the capture process, especially in dark conditions.</p>
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index f47ce79..b8b7d12 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -48,6 +48,7 @@
 import android.hardware.camera2.params.Face;
 import android.hardware.camera2.params.HighSpeedVideoConfiguration;
 import android.hardware.camera2.params.LensShadingMap;
+import android.hardware.camera2.params.ReprocessFormatsMap;
 import android.hardware.camera2.params.StreamConfiguration;
 import android.hardware.camera2.params.StreamConfigurationDuration;
 import android.hardware.camera2.params.StreamConfigurationMap;
@@ -830,11 +831,21 @@
                 CameraCharacteristics.SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
         StreamConfigurationDuration[] stallDurations = getBase(
                 CameraCharacteristics.SCALER_AVAILABLE_STALL_DURATIONS);
+        StreamConfiguration[] depthConfigurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS);
+        StreamConfigurationDuration[] depthMinFrameDurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS);
+        StreamConfigurationDuration[] depthStallDurations = getBase(
+                CameraCharacteristics.DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS);
         HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
                 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
+        ReprocessFormatsMap inputOutputFormatsMap = getBase(
+                CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
 
         return new StreamConfigurationMap(
-                configurations, minFrameDurations, stallDurations, highSpeedVideoConfigurations);
+                configurations, minFrameDurations, stallDurations,
+                depthConfigurations, depthMinFrameDurations, depthStallDurations,
+                highSpeedVideoConfigurations, inputOutputFormatsMap);
     }
 
     private <T> Integer getMaxRegions(Key<T> key) {
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 0a4ed39..7aa9787 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -18,6 +18,7 @@
 package android.hardware.camera2.params;
 
 import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.utils.HashCodeHelpers;
 import android.util.Log;
 import android.view.Surface;
 import android.os.Parcel;
@@ -159,6 +160,35 @@
         mSurface.writeToParcel(dest, flags);
     }
 
+    /**
+     * Check if this {@link OutputConfiguration} is equal to another {@link OutputConfiguration}.
+     *
+     * <p>Two output configurations are only equal if and only if the underlying surface and
+     * all other configuration parameters are equal. </p>
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        } else if (this == obj) {
+            return true;
+        } else if (obj instanceof OutputConfiguration) {
+            final OutputConfiguration other = (OutputConfiguration) obj;
+            return (mSurface == other.mSurface && mRotation == other.mRotation);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mSurface.hashCode(), mRotation);
+    }
+
     private static final String TAG = "OutputConfiguration";
     private final Surface mSurface;
     private final int mRotation;
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index f5304f8..c231692 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -89,11 +89,28 @@
             StreamConfiguration[] configurations,
             StreamConfigurationDuration[] minFrameDurations,
             StreamConfigurationDuration[] stallDurations,
-            HighSpeedVideoConfiguration[] highSpeedVideoConfigurations) {
-
+            StreamConfiguration[] depthConfigurations,
+            StreamConfigurationDuration[] depthMinFrameDurations,
+            StreamConfigurationDuration[] depthStallDurations,
+            HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
+            ReprocessFormatsMap inputOutputFormatsMap) {
         mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
         mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations");
         mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations");
+
+        if (depthConfigurations == null) {
+            mDepthConfigurations = new StreamConfiguration[0];
+            mDepthMinFrameDurations = new StreamConfigurationDuration[0];
+            mDepthStallDurations = new StreamConfigurationDuration[0];
+        } else {
+            mDepthConfigurations = checkArrayElementsNotNull(depthConfigurations,
+                    "depthConfigurations");
+            mDepthMinFrameDurations = checkArrayElementsNotNull(depthMinFrameDurations,
+                    "depthMinFrameDurations");
+            mDepthStallDurations = checkArrayElementsNotNull(depthStallDurations,
+                    "depthStallDurations");
+        }
+
         if (highSpeedVideoConfigurations == null) {
             mHighSpeedVideoConfigurations = new HighSpeedVideoConfiguration[0];
         } else {
@@ -110,9 +127,24 @@
             if (count == null) {
                 count = 0;
             }
-            count = count + 1;
 
-            map.put(config.getFormat(), count);
+            map.put(config.getFormat(), count + 1);
+        }
+
+        // For each depth format, track how many sizes there are available to configure
+        for (StreamConfiguration config : mDepthConfigurations) {
+            if (!config.isOutput()) {
+                // Ignoring input depth configs
+                continue;
+            }
+
+            Integer count = mDepthOutputFormats.get(config.getFormat());
+
+            if (count == null) {
+                count = 0;
+            }
+
+            mDepthOutputFormats.put(config.getFormat(), count + 1);
         }
 
         if (!mOutputFormats.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
@@ -135,6 +167,8 @@
             }
             mHighSpeedVideoFpsRangeMap.put(fpsRange, sizeCount + 1);
         }
+
+        mInputOutputFormatsMap = inputOutputFormatsMap;
     }
 
     /**
@@ -156,6 +190,33 @@
     }
 
     /**
+     * Get the image {@code format} output formats for a reprocessing input format.
+     *
+     * <p>When submitting a {@link CaptureRequest} with an input Surface of a given format,
+     * the only allowed target outputs of the {@link CaptureRequest} are the ones with a format
+     * listed in the return value of this method. Including any other output Surface as a target
+     * will throw an IllegalArgumentException. If no output format is supported given the input
+     * format, an empty int[] will be returned.</p>
+     *
+     * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
+     * or in {@link PixelFormat} (and there is no possibility of collision).</p>
+     *
+     * <p>Formats listed in this array are guaranteed to return true if queried with
+     * {@link #isOutputSupportedFor(int)}.</p>
+     *
+     * @return an array of integer format
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     */
+    public final int[] getValidOutputFormatsForInput(int inputFormat) {
+        if (mInputOutputFormatsMap == null) {
+            return new int[0];
+        }
+        return mInputOutputFormatsMap.getOutputs(inputFormat);
+    }
+
+    /**
      * Get the image {@code format} input formats in this stream configuration.
      *
      * <p>All image formats returned by this function will be defined in either {@link ImageFormat}
@@ -165,8 +226,6 @@
      *
      * @see ImageFormat
      * @see PixelFormat
-     *
-     * @hide
      */
     public final int[] getInputFormats() {
         return getPublicFormats(/*output*/false);
@@ -180,8 +239,6 @@
      *
      * @param format a format from {@link #getInputFormats}
      * @return a non-empty array of sizes, or {@code null} if the format was not available.
-     *
-     * @hide
      */
     public Size[] getInputSizes(final int format) {
         return getPublicFormatSizes(format, /*output*/false);
@@ -214,8 +271,13 @@
     public boolean isOutputSupportedFor(int format) {
         checkArgumentFormat(format);
 
-        format = imageFormatToInternal(format);
-        return getFormatsMap(/*output*/true).containsKey(format);
+        int internalFormat = imageFormatToInternal(format);
+        int dataspace = imageFormatToDataspace(format);
+        if (dataspace == HAL_DATASPACE_DEPTH) {
+            return mDepthOutputFormats.containsKey(internalFormat);
+        } else {
+            return getFormatsMap(/*output*/true).containsKey(internalFormat);
+        }
     }
 
     /**
@@ -353,12 +415,11 @@
      * Get a list of sizes compatible with {@code klass} to use as an output.
      *
      * <p>Since some of the supported classes may support additional formats beyond
-     * an opaque/implementation-defined (under-the-hood) format; this function only returns
-     * sizes for the implementation-defined format.</p>
-     *
-     * <p>Some classes such as {@link android.media.ImageReader} may only support user-defined
-     * formats; in particular {@link #isOutputSupportedFor(Class)} will return {@code true} for
-     * that class and this method will return an empty array (but not {@code null}).</p>
+     * {@link ImageFormat#PRIVATE}; this function only returns
+     * sizes for {@link ImageFormat#PRIVATE}. For example, {@link android.media.ImageReader}
+     * supports {@link ImageFormat#YUV_420_888} and {@link ImageFormat#PRIVATE}, this method will
+     * only return the sizes for {@link ImageFormat#PRIVATE} for {@link android.media.ImageReader}
+     * class .</p>
      *
      * <p>If a well-defined format such as {@code NV21} is required, use
      * {@link #getOutputSizes(int)} instead.</p>
@@ -369,24 +430,21 @@
      * @param klass
      *          a non-{@code null} {@link Class} object reference
      * @return
-     *          an array of supported sizes for implementation-defined formats,
-     *          or {@code null} iff the {@code klass} is not a supported output
+     *          an array of supported sizes for {@link ImageFormat#PRIVATE} format,
+     *          or {@code null} iff the {@code klass} is not a supported output.
+     *
      *
      * @throws NullPointerException if {@code klass} was {@code null}
      *
      * @see #isOutputSupportedFor(Class)
      */
     public <T> Size[] getOutputSizes(Class<T> klass) {
-        // Image reader is "supported", but never for implementation-defined formats; return empty
-        if (android.media.ImageReader.class.isAssignableFrom(klass)) {
-            return new Size[0];
-        }
-
         if (isOutputSupportedFor(klass) == false) {
             return null;
         }
 
-        return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /*output*/true);
+        return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+                HAL_DATASPACE_UNKNOWN,/*output*/true);
     }
 
     /**
@@ -599,14 +657,17 @@
         checkNotNull(size, "size must not be null");
         checkArgumentFormatSupported(format, /*output*/true);
 
-        return getInternalFormatDuration(imageFormatToInternal(format), size, DURATION_MIN_FRAME);
+        return getInternalFormatDuration(imageFormatToInternal(format),
+                imageFormatToDataspace(format),
+                size,
+                DURATION_MIN_FRAME);
     }
 
     /**
      * Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
      * for the class/size combination (in nanoseconds).
      *
-     * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+     * <p>This assumes a the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
      * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
      *
      * <p>{@code klass} should be one of the ones which is supported by
@@ -652,6 +713,7 @@
         }
 
         return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+                HAL_DATASPACE_UNKNOWN,
                 size, DURATION_MIN_FRAME);
     }
 
@@ -741,13 +803,15 @@
         checkArgumentFormatSupported(format, /*output*/true);
 
         return getInternalFormatDuration(imageFormatToInternal(format),
-                size, DURATION_STALL);
+                imageFormatToDataspace(format),
+                size,
+                DURATION_STALL);
     }
 
     /**
      * Get the stall duration for the class/size combination (in nanoseconds).
      *
-     * <p>This assumes a the {@code klass} is set up to use an implementation-defined format.
+     * <p>This assumes a the {@code klass} is set up to use {@link ImageFormat#PRIVATE}.
      * For user-defined formats, use {@link #getOutputMinFrameDuration(int, Size)}.</p>
      *
      * <p>{@code klass} should be one of the ones with a non-empty array returned by
@@ -778,7 +842,7 @@
         }
 
         return getInternalFormatDuration(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
-                size, DURATION_STALL);
+                HAL_DATASPACE_UNKNOWN, size, DURATION_STALL);
     }
 
     /**
@@ -857,6 +921,7 @@
             case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
             case HAL_PIXEL_FORMAT_BLOB:
             case HAL_PIXEL_FORMAT_RAW_OPAQUE:
+            case HAL_PIXEL_FORMAT_Y16:
                 return format;
             case ImageFormat.JPEG:
                 throw new IllegalArgumentException(
@@ -896,22 +961,23 @@
     }
 
     /**
-     * Convert a public-visible {@code ImageFormat} into an internal format
-     * compatible with {@code graphics.h}.
+     * Convert an internal format compatible with {@code graphics.h} into public-visible
+     * {@code ImageFormat}. This assumes the dataspace of the format is not HAL_DATASPACE_DEPTH.
      *
      * <p>In particular these formats are converted:
      * <ul>
-     * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG
+     * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.JPEG</li>
      * </ul>
      * </p>
      *
-     * <p>Passing in an implementation-defined format which has no public equivalent will fail;
+     * <p>Passing in a format which has no public equivalent will fail;
      * as will passing in a public format which has a different internal format equivalent.
      * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
      *
      * <p>All other formats are returned as-is, no further invalid check is performed.</p>
      *
-     * <p>This function is the dual of {@link #imageFormatToInternal}.</p>
+     * <p>This function is the dual of {@link #imageFormatToInternal} for dataspaces other than
+     * HAL_DATASPACE_DEPTH.</p>
      *
      * @param format image format from {@link ImageFormat} or {@link PixelFormat}
      * @return the converted image formats
@@ -931,11 +997,57 @@
             case ImageFormat.JPEG:
                 throw new IllegalArgumentException(
                         "ImageFormat.JPEG is an unknown internal format");
+            default:
+                return format;
+        }
+    }
+
+    /**
+     * Convert an internal format compatible with {@code graphics.h} into public-visible
+     * {@code ImageFormat}. This assumes the dataspace of the format is HAL_DATASPACE_DEPTH.
+     *
+     * <p>In particular these formats are converted:
+     * <ul>
+     * <li>HAL_PIXEL_FORMAT_BLOB => ImageFormat.DEPTH_POINT_CLOUD
+     * <li>HAL_PIXEL_FORMAT_Y16 => ImageFormat.DEPTH16
+     * </ul>
+     * </p>
+     *
+     * <p>Passing in an implementation-defined format which has no public equivalent will fail;
+     * as will passing in a public format which has a different internal format equivalent.
+     * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
+     *
+     * <p>All other formats are returned as-is, no further invalid check is performed.</p>
+     *
+     * <p>This function is the dual of {@link #imageFormatToInternal} for formats associated with
+     * HAL_DATASPACE_DEPTH.</p>
+     *
+     * @param format image format from {@link ImageFormat} or {@link PixelFormat}
+     * @return the converted image formats
+     *
+     * @throws IllegalArgumentException
+     *          if {@code format} is {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED} or
+     *          {@link ImageFormat#JPEG}
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     * @see #checkArgumentFormat
+     */
+    static int depthFormatToPublic(int format) {
+        switch (format) {
+            case HAL_PIXEL_FORMAT_BLOB:
+                return ImageFormat.DEPTH_POINT_CLOUD;
+            case HAL_PIXEL_FORMAT_Y16:
+                return ImageFormat.DEPTH16;
+            case ImageFormat.JPEG:
+                throw new IllegalArgumentException(
+                        "ImageFormat.JPEG is an unknown internal format");
             case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
                 throw new IllegalArgumentException(
                         "IMPLEMENTATION_DEFINED must not leak to public API");
             default:
-                return format;
+                throw new IllegalArgumentException(
+                        "Unknown DATASPACE_DEPTH format " + format);
         }
     }
 
@@ -966,6 +1078,49 @@
      * <p>In particular these formats are converted:
      * <ul>
      * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB
+     * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_PIXEL_FORMAT_BLOB
+     * <li>ImageFormat.DEPTH16 => HAL_PIXEL_FORMAT_Y16
+     * </ul>
+     * </p>
+     *
+     * <p>Passing in an internal format which has a different public format equivalent will fail.
+     * See {@link #checkArgumentFormat} for more details about a legal public format.</p>
+     *
+     * <p>All other formats are returned as-is, no invalid check is performed.</p>
+     *
+     * <p>This function is the dual of {@link #imageFormatToPublic}.</p>
+     *
+     * @param format public image format from {@link ImageFormat} or {@link PixelFormat}
+     * @return the converted image formats
+     *
+     * @see ImageFormat
+     * @see PixelFormat
+     *
+     * @throws IllegalArgumentException
+     *              if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}
+     */
+    static int imageFormatToInternal(int format) {
+        switch (format) {
+            case ImageFormat.JPEG:
+            case ImageFormat.DEPTH_POINT_CLOUD:
+                return HAL_PIXEL_FORMAT_BLOB;
+            case ImageFormat.DEPTH16:
+                return HAL_PIXEL_FORMAT_Y16;
+            default:
+                return format;
+        }
+    }
+
+    /**
+     * Convert a public format compatible with {@code ImageFormat} to an internal dataspace
+     * from {@code graphics.h}.
+     *
+     * <p>In particular these formats are converted:
+     * <ul>
+     * <li>ImageFormat.JPEG => HAL_DATASPACE_JFIF
+     * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
+     * <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
+     * <li>others => HAL_DATASPACE_UNKNOWN
      * </ul>
      * </p>
      *
@@ -986,15 +1141,15 @@
      * @throws IllegalArgumentException
      *              if {@code format} was {@code HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED}
      */
-    static int imageFormatToInternal(int format) {
+    static int imageFormatToDataspace(int format) {
         switch (format) {
             case ImageFormat.JPEG:
-                return HAL_PIXEL_FORMAT_BLOB;
-            case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
-                throw new IllegalArgumentException(
-                        "IMPLEMENTATION_DEFINED is not allowed via public API");
+                return HAL_DATASPACE_JFIF;
+            case ImageFormat.DEPTH_POINT_CLOUD:
+            case ImageFormat.DEPTH16:
+                return HAL_DATASPACE_DEPTH;
             default:
-                return format;
+                return HAL_DATASPACE_UNKNOWN;
         }
     }
 
@@ -1027,13 +1182,16 @@
             return null;
         }
 
-        format = imageFormatToInternal(format);
+        int internalFormat = imageFormatToInternal(format);
+        int dataspace = imageFormatToDataspace(format);
 
-        return getInternalFormatSizes(format, output);
+        return getInternalFormatSizes(internalFormat, dataspace, output);
     }
 
-    private Size[] getInternalFormatSizes(int format, boolean output) {
-        HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
+    private Size[] getInternalFormatSizes(int format, int dataspace, boolean output) {
+
+        HashMap<Integer, Integer> formatsMap =
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthOutputFormats : getFormatsMap(output);
 
         Integer sizesCount = formatsMap.get(format);
         if (sizesCount == null) {
@@ -1044,7 +1202,11 @@
         Size[] sizes = new Size[len];
         int sizeIndex = 0;
 
-        for (StreamConfiguration config : mConfigurations) {
+        StreamConfiguration[] configurations =
+                (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+
+
+        for (StreamConfiguration config : configurations) {
             if (config.getFormat() == format && config.isOutput() == output) {
                 sizes[sizeIndex++] = config.getSize();
             }
@@ -1065,17 +1227,20 @@
         int i = 0;
 
         for (int format : getFormatsMap(output).keySet()) {
-            if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&
-                format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
-                formats[i++] = format;
+            if (format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+                formats[i++] = imageFormatToPublic(format);
             }
         }
-
+        if (output) {
+            for (int format : mDepthOutputFormats.keySet()) {
+                formats[i++] = depthFormatToPublic(format);
+            }
+        }
         if (formats.length != i) {
             throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
         }
 
-        return imageFormatToPublic(formats);
+        return formats;
     }
 
     /** Get the format -> size count map for either output or input formats */
@@ -1083,14 +1248,14 @@
         return output ? mOutputFormats : mInputFormats;
     }
 
-    private long getInternalFormatDuration(int format, Size size, int duration) {
+    private long getInternalFormatDuration(int format, int dataspace, Size size, int duration) {
         // assume format is already checked, since its internal
 
-        if (!arrayContains(getInternalFormatSizes(format, /*output*/true), size)) {
+        if (!arrayContains(getInternalFormatSizes(format, dataspace, /*output*/true), size)) {
             throw new IllegalArgumentException("size was not supported");
         }
 
-        StreamConfigurationDuration[] durations = getDurations(duration);
+        StreamConfigurationDuration[] durations = getDurations(duration, dataspace);
 
         for (StreamConfigurationDuration configurationDuration : durations) {
             if (configurationDuration.getFormat() == format &&
@@ -1109,12 +1274,14 @@
      * @see #DURATION_MIN_FRAME
      * @see #DURATION_STALL
      * */
-    private StreamConfigurationDuration[] getDurations(int duration) {
+    private StreamConfigurationDuration[] getDurations(int duration, int dataspace) {
         switch (duration) {
             case DURATION_MIN_FRAME:
-                return mMinFrameDurations;
+                return (dataspace == HAL_DATASPACE_DEPTH) ?
+                        mDepthMinFrameDurations : mMinFrameDurations;
             case DURATION_STALL:
-                return mStallDurations;
+                return (dataspace == HAL_DATASPACE_DEPTH) ?
+                        mDepthStallDurations : mStallDurations;
             default:
                 throw new IllegalArgumentException("duration was invalid");
         }
@@ -1125,12 +1292,12 @@
         HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
 
         int size = formatsMap.size();
-        if (formatsMap.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
-            size -= 1;
-        }
         if (formatsMap.containsKey(HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
             size -= 1;
         }
+        if (output) {
+            size += mDepthOutputFormats.size();
+        }
 
         return size;
     }
@@ -1153,10 +1320,14 @@
     private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
     private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
     private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24;
+    private static final int HAL_PIXEL_FORMAT_Y16 = 0x20363159;
+
+    private static final int HAL_DATASPACE_UNKNOWN = 0x0;
+    private static final int HAL_DATASPACE_JFIF = 0x101;
+    private static final int HAL_DATASPACE_DEPTH = 0x1000;
 
     /**
-     * @see #getDurations(int)
-     * @see #getDurationDefault(int)
+     * @see #getDurations(int, int)
      */
     private static final int DURATION_MIN_FRAME = 0;
     private static final int DURATION_STALL = 1;
@@ -1164,7 +1335,13 @@
     private final StreamConfiguration[] mConfigurations;
     private final StreamConfigurationDuration[] mMinFrameDurations;
     private final StreamConfigurationDuration[] mStallDurations;
+
+    private final StreamConfiguration[] mDepthConfigurations;
+    private final StreamConfigurationDuration[] mDepthMinFrameDurations;
+    private final StreamConfigurationDuration[] mDepthStallDurations;
+
     private final HighSpeedVideoConfiguration[] mHighSpeedVideoConfigurations;
+    private final ReprocessFormatsMap mInputOutputFormatsMap;
 
     /** ImageFormat -> num output sizes mapping */
     private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats =
@@ -1172,6 +1349,9 @@
     /** ImageFormat -> num input sizes mapping */
     private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats =
             new HashMap<Integer, Integer>();
+    /** ImageFormat -> num depth output sizes mapping */
+    private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mDepthOutputFormats =
+            new HashMap<Integer, Integer>();
     /** High speed video Size -> FPS range count mapping*/
     private final HashMap</*HighSpeedVideoSize*/Size, /*Count*/Integer> mHighSpeedVideoSizeMap =
             new HashMap<Size, Integer>();
@@ -1180,3 +1360,4 @@
             mHighSpeedVideoFpsRangeMap = new HashMap<Range<Integer>, Integer>();
 
 }
+
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/hardware/fingerprint/Fingerprint.aidl
similarity index 94%
rename from core/java/android/service/fingerprint/Fingerprint.aidl
rename to core/java/android/hardware/fingerprint/Fingerprint.aidl
index c9fd989..4743354 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/core/java/android/hardware/fingerprint/Fingerprint.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 // @hide
 parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/hardware/fingerprint/Fingerprint.java
similarity index 98%
rename from core/java/android/service/fingerprint/Fingerprint.java
rename to core/java/android/hardware/fingerprint/Fingerprint.java
index 37552eb..c307634 100644
--- a/core/java/android/service/fingerprint/Fingerprint.java
+++ b/core/java/android/hardware/fingerprint/Fingerprint.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
similarity index 99%
rename from core/java/android/service/fingerprint/FingerprintManager.java
rename to core/java/android/hardware/fingerprint/FingerprintManager.java
index bb90e40..e3572a2 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.app.ActivityManagerNative;
 import android.content.ContentResolver;
@@ -28,7 +28,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
 import android.util.Log;
 import android.util.Slog;
 
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/hardware/fingerprint/FingerprintUtils.java
similarity index 98%
rename from core/java/android/service/fingerprint/FingerprintUtils.java
rename to core/java/android/hardware/fingerprint/FingerprintUtils.java
index 62acbb9..ae3d4a4 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/hardware/fingerprint/FingerprintUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.content.ContentResolver;
 import android.provider.Settings;
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
similarity index 92%
rename from core/java/android/service/fingerprint/IFingerprintService.aidl
rename to core/java/android/hardware/fingerprint/IFingerprintService.aidl
index e5d3ad4..c5a45e2 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -13,11 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.os.Bundle;
-import android.service.fingerprint.IFingerprintServiceReceiver;
-import android.service.fingerprint.Fingerprint;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.Fingerprint;
 import java.util.List;
 
 /**
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
similarity index 96%
rename from core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
rename to core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index f025064..e82395f 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
+package android.hardware.fingerprint;
 
 import android.os.Bundle;
 import android.os.UserHandle;
diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java
index 5696839..e902443 100644
--- a/core/java/android/inputmethodservice/ExtractEditLayout.java
+++ b/core/java/android/inputmethodservice/ExtractEditLayout.java
@@ -163,6 +163,8 @@
             mCallback.onDestroyActionMode(this);
             mCallback = null;
 
+            mMenu.close();
+
             mExtractActionButton.setVisibility(VISIBLE);
             mEditButton.setVisibility(INVISIBLE);
 
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index bf3d9aa..f305b2a 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -366,7 +366,6 @@
     public String toSafeString() {
         String scheme = getScheme();
         String ssp = getSchemeSpecificPart();
-        String authority = null;
         if (scheme != null) {
             if (scheme.equalsIgnoreCase("tel") || scheme.equalsIgnoreCase("sip")
                     || scheme.equalsIgnoreCase("sms") || scheme.equalsIgnoreCase("smsto")
@@ -385,9 +384,11 @@
                     }
                 }
                 return builder.toString();
-            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
-                ssp = null;
-                authority = "//" + getAuthority() + "/...";
+            } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")
+                    || scheme.equalsIgnoreCase("ftp")) {
+                ssp = "//" + ((getHost() != null) ? getHost() : "")
+                        + ((getPort() != -1) ? (":" + getPort()) : "")
+                        + "/...";
             }
         }
         // Not a sensitive scheme, but let's still be conservative about
@@ -401,9 +402,6 @@
         if (ssp != null) {
             builder.append(ssp);
         }
-        if (authority != null) {
-            builder.append(authority);
-        }
         return builder.toString();
     }
 
diff --git a/core/java/android/net/WifiKey.java b/core/java/android/net/WifiKey.java
index 71df2f9..99de99e 100644
--- a/core/java/android/net/WifiKey.java
+++ b/core/java/android/net/WifiKey.java
@@ -33,7 +33,8 @@
 public class WifiKey implements Parcelable {
 
     // Patterns used for validation.
-    private static final Pattern SSID_PATTERN = Pattern.compile("(\".*\")|(0x[\\p{XDigit}]+)");
+    private static final Pattern SSID_PATTERN = Pattern.compile("(\".*\")|(0x[\\p{XDigit}]+)",
+            Pattern.DOTALL);
     private static final Pattern BSSID_PATTERN =
             Pattern.compile("([\\p{XDigit}]{2}:){5}[\\p{XDigit}]{2}");
 
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index bd5a3922..cccc4be 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -16,10 +16,12 @@
 
 package android.os;
 
+import android.content.Context;
 import android.os.BatteryProperty;
 import android.os.IBatteryPropertiesRegistrar;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import com.android.internal.app.IBatteryStats;
 
 /**
  * The BatteryManager class contains strings and constants used for values
@@ -128,6 +130,26 @@
     public static final int BATTERY_PLUGGED_ANY =
             BATTERY_PLUGGED_AC | BATTERY_PLUGGED_USB | BATTERY_PLUGGED_WIRELESS;
 
+    /**
+     * Sent when the device's battery has started charging (or has reached full charge
+     * and the device is on power).  This is a good time to do work that you would like to
+     * avoid doing while on battery (that is to avoid draining the user's battery due to
+     * things they don't care enough about).
+     *
+     * This is paired with {@link #ACTION_DISCHARGING}.  The current state can always
+     * be retrieved with {@link #isCharging()}.
+     */
+    public static final String ACTION_CHARGING = "android.os.action.CHARGING";
+
+    /**
+     * Sent when the device's battery may be discharging, so apps should avoid doing
+     * extraneous work that would cause it to discharge faster.
+     *
+     * This is paired with {@link #ACTION_CHARGING}.  The current state can always
+     * be retrieved with {@link #isCharging()}.
+     */
+    public static final String ACTION_DISCHARGING = "android.os.action.DISCHARGING";
+
     /*
      * Battery property identifiers.  These must match the values in
      * frameworks/native/include/batteryservice/BatteryService.h
@@ -162,17 +184,34 @@
      */
     public static final int BATTERY_PROPERTY_ENERGY_COUNTER = 5;
 
+    private final IBatteryStats mBatteryStats;
     private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
 
     /**
      * @removed Was previously made visible by accident.
      */
     public BatteryManager() {
+        mBatteryStats = IBatteryStats.Stub.asInterface(
+                ServiceManager.getService(BatteryStats.SERVICE_NAME));
         mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
                 ServiceManager.getService("batteryproperties"));
     }
 
     /**
+     * Return true if the battery is currently considered to be charging.  This means that
+     * the device is plugged in and is supplying sufficient power that the battery level is
+     * going up (or the battery is fully charged).  Changes in this state are matched by
+     * broadcasts of {@link #ACTION_CHARGING} and {@link #ACTION_DISCHARGING}.
+     */
+    public boolean isCharging() {
+        try {
+            return mBatteryStats.isCharging();
+        } catch (RemoteException e) {
+            return true;
+        }
+    }
+
+    /**
      * Query a battery property from the batteryproperties service.
      *
      * Returns the requested value, or Long.MIN_VALUE if property not
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 8b3ecae..c7edb1a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -269,6 +269,15 @@
         public abstract long getTotalTimeLocked(long elapsedRealtimeUs, int which);
 
         /**
+         * Returns the total time in microseconds associated with this Timer since the
+         * 'mark' was last set.
+         *
+         * @param elapsedRealtimeUs current elapsed realtime of system in microseconds
+         * @return a time in microseconds
+         */
+        public abstract long getTimeSinceMarkLocked(long elapsedRealtimeUs);
+
+        /**
          * Temporary for debugging.
          */
         public abstract void logState(Printer pw, String prefix);
@@ -332,7 +341,17 @@
          * @return a Map from Strings to Uid.Pkg objects.
          */
         public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
-        
+
+        /**
+         * Returns the time in milliseconds that this app kept the WiFi controller in the
+         * specified state <code>type</code>.
+         * @param type one of {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, or
+         *             {@link #CONTROLLER_TX_TIME}.
+         * @param which one of {@link #STATS_CURRENT}, {@link #STATS_SINCE_CHARGED}, or
+         *              {@link #STATS_SINCE_UNPLUGGED}.
+         */
+        public abstract long getWifiControllerActivity(int type, int which);
+
         /**
          * {@hide}
          */
@@ -1046,6 +1065,7 @@
         public static final int STATE_SCREEN_ON_FLAG = 1<<20;
         public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19;
         public static final int STATE_PHONE_IN_CALL_FLAG = 1<<18;
+        public static final int STATE_CHARGING_FLAG = 1<<17;
         public static final int STATE_BLUETOOTH_ON_FLAG = 1<<16;
 
         public static final int MOST_INTERESTING_STATES =
@@ -1732,6 +1752,7 @@
         new BitDescription(HistoryItem.STATE_SCREEN_ON_FLAG, "screen", "S"),
         new BitDescription(HistoryItem.STATE_BATTERY_PLUGGED_FLAG, "plugged", "BP"),
         new BitDescription(HistoryItem.STATE_PHONE_IN_CALL_FLAG, "phone_in_call", "Pcl"),
+        new BitDescription(HistoryItem.STATE_CHARGING_FLAG, "charging", "ch"),
         new BitDescription(HistoryItem.STATE_BLUETOOTH_ON_FLAG, "bluetooth", "b"),
         new BitDescription(HistoryItem.STATE_DATA_CONNECTION_MASK,
                 HistoryItem.STATE_DATA_CONNECTION_SHIFT, "data_conn", "Pcn",
@@ -1914,7 +1935,6 @@
     public static final int NETWORK_MOBILE_TX_DATA = 1;
     public static final int NETWORK_WIFI_RX_DATA = 2;
     public static final int NETWORK_WIFI_TX_DATA = 3;
-
     public static final int NUM_NETWORK_ACTIVITY_TYPES = NETWORK_WIFI_TX_DATA + 1;
 
     public abstract long getNetworkActivityBytes(int type, int which);
@@ -1923,10 +1943,39 @@
     public static final int CONTROLLER_IDLE_TIME = 0;
     public static final int CONTROLLER_RX_TIME = 1;
     public static final int CONTROLLER_TX_TIME = 2;
-    public static final int CONTROLLER_ENERGY = 3;
-    public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_ENERGY + 1;
+    public static final int CONTROLLER_POWER_DRAIN = 3;
+    public static final int NUM_CONTROLLER_ACTIVITY_TYPES = CONTROLLER_POWER_DRAIN + 1;
 
+    /**
+     * Returns true if the BatteryStats object has detailed bluetooth power reports.
+     * When true, calling {@link #getBluetoothControllerActivity(int, int)} will yield the
+     * actual power data.
+     */
+    public abstract boolean hasBluetoothActivityReporting();
+
+    /**
+     * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and
+     * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the
+     * respective state.
+     * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in
+     * milli-ampere-milliseconds (mAms).
+     */
     public abstract long getBluetoothControllerActivity(int type, int which);
+
+    /**
+     * Returns true if the BatteryStats object has detailed WiFi power reports.
+     * When true, calling {@link #getWifiControllerActivity(int, int)} will yield the
+     * actual power data.
+     */
+    public abstract boolean hasWifiActivityReporting();
+
+    /**
+     * For {@link #CONTROLLER_IDLE_TIME}, {@link #CONTROLLER_RX_TIME}, and
+     * {@link #CONTROLLER_TX_TIME}, returns the time spent (in milliseconds) in the
+     * respective state.
+     * For {@link #CONTROLLER_POWER_DRAIN}, returns the power used by the controller in
+     * milli-ampere-milliseconds (mAms).
+     */
     public abstract long getWifiControllerActivity(int type, int which);
 
     /**
@@ -2618,7 +2667,7 @@
                         label = "???";
                 }
                 dumpLine(pw, uid, category, POWER_USE_ITEM_DATA, label,
-                        BatteryStatsHelper.makemAh(bs.value));
+                        BatteryStatsHelper.makemAh(bs.totalPowerMah));
             }
         }
 
@@ -3264,6 +3313,13 @@
 
         sb.setLength(0);
         sb.append(prefix);
+        sb.append("  WiFi Energy use: ").append(BatteryStatsHelper.makemAh(
+                getWifiControllerActivity(CONTROLLER_POWER_DRAIN, which) / (double)(1000*60*60)));
+        sb.append(" mAh");
+        pw.println(sb.toString());
+
+        sb.setLength(0);
+        sb.append(prefix);
                 sb.append("  Bluetooth on: "); formatTimeMs(sb, bluetoothOnTime / 1000);
                 sb.append("("); sb.append(formatRatioLocked(bluetoothOnTime, whichBatteryRealtime));
                 sb.append(")");
@@ -3376,48 +3432,48 @@
                 final BatterySipper bs = sippers.get(i);
                 switch (bs.drainType) {
                     case IDLE:
-                        pw.print(prefix); pw.print("    Idle: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Idle: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case CELL:
-                        pw.print(prefix); pw.print("    Cell standby: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Cell standby: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case PHONE:
-                        pw.print(prefix); pw.print("    Phone calls: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Phone calls: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case WIFI:
-                        pw.print(prefix); pw.print("    Wifi: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Wifi: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case BLUETOOTH:
-                        pw.print(prefix); pw.print("    Bluetooth: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Bluetooth: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case SCREEN:
-                        pw.print(prefix); pw.print("    Screen: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Screen: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case FLASHLIGHT:
-                        pw.print(prefix); pw.print("    Flashlight: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Flashlight: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case APP:
                         pw.print(prefix); pw.print("    Uid ");
                         UserHandle.formatUid(pw, bs.uidObj.getUid());
-                        pw.print(": "); printmAh(pw, bs.value); pw.println();
+                        pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println();
                         break;
                     case USER:
                         pw.print(prefix); pw.print("    User "); pw.print(bs.userId);
-                        pw.print(": "); printmAh(pw, bs.value); pw.println();
+                        pw.print(": "); printmAh(pw, bs.totalPowerMah); pw.println();
                         break;
                     case UNACCOUNTED:
-                        pw.print(prefix); pw.print("    Unaccounted: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Unaccounted: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                     case OVERCOUNTED:
-                        pw.print(prefix); pw.print("    Over-counted: "); printmAh(pw, bs.value);
+                        pw.print(prefix); pw.print("    Over-counted: "); printmAh(pw, bs.totalPowerMah);
                         pw.println();
                         break;
                 }
@@ -4415,7 +4471,7 @@
         if (!checkin) {
             pw.println(header);
         }
-        String[] lineArgs = new String[4];
+        String[] lineArgs = new String[5];
         for (int i=0; i<count; i++) {
             long duration = steps.getDurationAt(i);
             int level = steps.getLevelAt(i);
@@ -4430,7 +4486,7 @@
                         case Display.STATE_ON: lineArgs[2] = "s+"; break;
                         case Display.STATE_DOZE: lineArgs[2] = "sd"; break;
                         case Display.STATE_DOZE_SUSPEND: lineArgs[2] = "sds"; break;
-                        default: lineArgs[1] = "?"; break;
+                        default: lineArgs[2] = "?"; break;
                     }
                 } else {
                     lineArgs[2] = "";
@@ -4441,9 +4497,9 @@
                     lineArgs[3] = "";
                 }
                 if ((modMode&STEP_LEVEL_MODE_DEVICE_IDLE) == 0) {
-                    lineArgs[3] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
+                    lineArgs[4] = (initMode&STEP_LEVEL_MODE_DEVICE_IDLE) != 0 ? "i+" : "i-";
                 } else {
-                    lineArgs[3] = "";
+                    lineArgs[4] = "";
                 }
                 dumpLine(pw, 0 /* uid */, "i" /* category */, header, (Object[])lineArgs);
             } else {
@@ -4459,7 +4515,7 @@
                         case Display.STATE_ON: pw.print("screen-on"); break;
                         case Display.STATE_DOZE: pw.print("screen-doze"); break;
                         case Display.STATE_DOZE_SUSPEND: pw.print("screen-doze-suspend"); break;
-                        default: lineArgs[1] = "screen-?"; break;
+                        default: pw.print("screen-?"); break;
                     }
                     haveModes = true;
                 }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 2db976e..2eb97f1 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -80,11 +80,11 @@
 
         public File[] getExternalDirs() {
             final StorageVolume[] volumes = StorageManager.getVolumeList(mUserId);
-            final File[] dirs = new File[volumes.length];
+            final File[] files = new File[volumes.length];
             for (int i = 0; i < volumes.length; i++) {
-                dirs[i] = volumes[i].getPathFile();
+                files[i] = volumes[i].getPathFile();
             }
-            return dirs;
+            return files;
         }
 
         @Deprecated
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 236003b..c2fd3c3 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -38,6 +38,7 @@
     List<UserInfo> getProfiles(int userHandle, boolean enabledOnly);
     UserInfo getProfileParent(int userHandle);
     UserInfo getUserInfo(int userHandle);
+    long getUserCreationTime(int userHandle);
     boolean isRestricted();
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3601a1c..afd9950 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1320,4 +1320,19 @@
         }
         return new Bundle();
     }
+
+    /**
+     * Returns creation time of the user or of a managed profile associated with the calling user.
+     * @param userHandle user handle of the user or a managed profile associated with the
+     *                   calling user.
+     * @return creation time in milliseconds since Epoch time.
+     */
+    public long getUserCreationTime(int userHandle) {
+        try {
+            return mService.getUserCreationTime(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user creation time", re);
+            return 0;
+        }
+    }
 }
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/os/storage/DiskInfo.aidl
similarity index 89%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to core/java/android/os/storage/DiskInfo.aidl
index c9fd989..5126c19 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/core/java/android/os/storage/DiskInfo.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package android.os.storage;
+
+parcelable DiskInfo;
diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
new file mode 100644
index 0000000..56c55f1
--- /dev/null
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DebugUtils;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.io.CharArrayWriter;
+
+/**
+ * Information about a physical disk which may contain one or more
+ * {@link VolumeInfo}.
+ *
+ * @hide
+ */
+public class DiskInfo implements Parcelable {
+    public static final int FLAG_ADOPTABLE = 1 << 0;
+    public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
+    public static final int FLAG_SD = 1 << 2;
+    public static final int FLAG_USB = 1 << 3;
+
+    public final String id;
+    public final int flags;
+    public long size;
+    public String label;
+    public String[] volumes;
+
+    public DiskInfo(String id, int flags) {
+        this.id = Preconditions.checkNotNull(id);
+        this.flags = flags;
+    }
+
+    public DiskInfo(Parcel parcel) {
+        id = parcel.readString();
+        flags = parcel.readInt();
+        size = parcel.readLong();
+        label = parcel.readString();
+        volumes = parcel.readStringArray();
+    }
+
+    public String getDescription(Context context) {
+        // TODO: splice vendor label into these strings
+        if ((flags & FLAG_SD) != 0) {
+            return context.getString(com.android.internal.R.string.storage_sd_card);
+        } else if ((flags & FLAG_USB) != 0) {
+            return context.getString(com.android.internal.R.string.storage_usb);
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        final CharArrayWriter writer = new CharArrayWriter();
+        dump(new IndentingPrintWriter(writer, "    ", 80));
+        return writer.toString();
+    }
+
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("DiskInfo:");
+        pw.increaseIndent();
+        pw.printPair("id", id);
+        pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
+        pw.printPair("size", size);
+        pw.printPair("label", label);
+        pw.printPair("volumes", volumes);
+        pw.decreaseIndent();
+        pw.println();
+    }
+
+    @Override
+    public DiskInfo clone() {
+        final Parcel temp = Parcel.obtain();
+        try {
+            writeToParcel(temp, 0);
+            temp.setDataPosition(0);
+            return CREATOR.createFromParcel(temp);
+        } finally {
+            temp.recycle();
+        }
+    }
+
+    public static final Creator<DiskInfo> CREATOR = new Creator<DiskInfo>() {
+        @Override
+        public DiskInfo createFromParcel(Parcel in) {
+            return new DiskInfo(in);
+        }
+
+        @Override
+        public DiskInfo[] newArray(int size) {
+            return new DiskInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(id);
+        parcel.writeInt(flags);
+        parcel.writeLong(size);
+        parcel.writeString(label);
+        parcel.writeStringArray(volumes);
+    }
+}
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index fef12d1..10ffd48 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -904,6 +904,131 @@
                 }
                 return;
             }
+
+            @Override
+            public DiskInfo[] getDisks() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                DiskInfo[] _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_getDisks, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.createTypedArray(DiskInfo.CREATOR);
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            @Override
+            public VolumeInfo[] getVolumes() throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                VolumeInfo[] _result;
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    mRemote.transact(Stub.TRANSACTION_getVolumes, _data, _reply, 0);
+                    _reply.readException();
+                    _result = _reply.createTypedArray(VolumeInfo.CREATOR);
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+                return _result;
+            }
+
+            @Override
+            public void mount(String volId) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(volId);
+                    mRemote.transact(Stub.TRANSACTION_mount, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void unmount(String volId) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(volId);
+                    mRemote.transact(Stub.TRANSACTION_unmount, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void format(String volId) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(volId);
+                    mRemote.transact(Stub.TRANSACTION_format, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void partitionPublic(String diskId) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(diskId);
+                    mRemote.transact(Stub.TRANSACTION_partitionPublic, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void partitionPrivate(String diskId) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(diskId);
+                    mRemote.transact(Stub.TRANSACTION_partitionPrivate, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void partitionMixed(String diskId, int ratio) throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeString(diskId);
+                    _data.writeInt(ratio);
+                    mRemote.transact(Stub.TRANSACTION_partitionMixed, _data, _reply, 0);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
         }
 
         private static final String DESCRIPTOR = "IMountService";
@@ -996,6 +1121,17 @@
 
         static final int TRANSACTION_waitForAsecScan = IBinder.FIRST_CALL_TRANSACTION + 43;
 
+        static final int TRANSACTION_getDisks = IBinder.FIRST_CALL_TRANSACTION + 44;
+        static final int TRANSACTION_getVolumes = IBinder.FIRST_CALL_TRANSACTION + 45;
+
+        static final int TRANSACTION_mount = IBinder.FIRST_CALL_TRANSACTION + 46;
+        static final int TRANSACTION_unmount = IBinder.FIRST_CALL_TRANSACTION + 47;
+        static final int TRANSACTION_format = IBinder.FIRST_CALL_TRANSACTION + 48;
+
+        static final int TRANSACTION_partitionPublic = IBinder.FIRST_CALL_TRANSACTION + 49;
+        static final int TRANSACTION_partitionPrivate = IBinder.FIRST_CALL_TRANSACTION + 50;
+        static final int TRANSACTION_partitionMixed = IBinder.FIRST_CALL_TRANSACTION + 51;
+
         /**
          * Cast an IBinder object into an IMountService interface, generating a
          * proxy if needed.
@@ -1421,6 +1557,63 @@
                     reply.writeNoException();
                     return true;
                 }
+                case TRANSACTION_getDisks: {
+                    data.enforceInterface(DESCRIPTOR);
+                    DiskInfo[] disks = getDisks();
+                    reply.writeNoException();
+                    reply.writeTypedArray(disks, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+                    return true;
+                }
+                case TRANSACTION_getVolumes: {
+                    data.enforceInterface(DESCRIPTOR);
+                    VolumeInfo[] volumes = getVolumes();
+                    reply.writeNoException();
+                    reply.writeTypedArray(volumes, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+                    return true;
+                }
+                case TRANSACTION_mount: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String volId = data.readString();
+                    mount(volId);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_unmount: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String volId = data.readString();
+                    unmount(volId);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_format: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String volId = data.readString();
+                    format(volId);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_partitionPublic: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String diskId = data.readString();
+                    partitionPublic(diskId);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_partitionPrivate: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String diskId = data.readString();
+                    partitionPrivate(diskId);
+                    reply.writeNoException();
+                    return true;
+                }
+                case TRANSACTION_partitionMixed: {
+                    data.enforceInterface(DESCRIPTOR);
+                    String diskId = data.readString();
+                    int ratio = data.readInt();
+                    partitionMixed(diskId, ratio);
+                    reply.writeNoException();
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -1707,4 +1900,15 @@
     public void runMaintenance() throws RemoteException;
 
     public void waitForAsecScan() throws RemoteException;
+
+    public DiskInfo[] getDisks() throws RemoteException;
+    public VolumeInfo[] getVolumes() throws RemoteException;
+
+    public void mount(String volId) throws RemoteException;
+    public void unmount(String volId) throws RemoteException;
+    public void format(String volId) throws RemoteException;
+
+    public void partitionPublic(String diskId) throws RemoteException;
+    public void partitionPrivate(String diskId) throws RemoteException;
+    public void partitionMixed(String diskId, int ratio) throws RemoteException;
 }
diff --git a/core/java/android/os/storage/IMountServiceListener.java b/core/java/android/os/storage/IMountServiceListener.java
index d5c5fa5..3965f9d 100644
--- a/core/java/android/os/storage/IMountServiceListener.java
+++ b/core/java/android/os/storage/IMountServiceListener.java
@@ -75,16 +75,22 @@
                 }
                 case TRANSACTION_onStorageStateChanged: {
                     data.enforceInterface(DESCRIPTOR);
-                    String path;
-                    path = data.readString();
-                    String oldState;
-                    oldState = data.readString();
-                    String newState;
-                    newState = data.readString();
+                    final String path = data.readString();
+                    final String oldState = data.readString();
+                    final String newState = data.readString();
                     this.onStorageStateChanged(path, oldState, newState);
                     reply.writeNoException();
                     return true;
                 }
+                case TRANSACTION_onVolumeStateChanged: {
+                    data.enforceInterface(DESCRIPTOR);
+                    final VolumeInfo vol = (VolumeInfo) data.readParcelable(null);
+                    final int oldState = data.readInt();
+                    final int newState = data.readInt();
+                    onVolumeStateChanged(vol, oldState, newState);
+                    reply.writeNoException();
+                    return true;
+                }
             }
             return super.onTransact(code, data, reply, flags);
         }
@@ -116,7 +122,7 @@
                     _data.writeInterfaceToken(DESCRIPTOR);
                     _data.writeInt(((connected) ? (1) : (0)));
                     mRemote.transact(Stub.TRANSACTION_onUsbMassStorageConnectionChanged, _data,
-                            _reply, 0);
+                            _reply, android.os.IBinder.FLAG_ONEWAY);
                     _reply.readException();
                 } finally {
                     _reply.recycle();
@@ -142,7 +148,27 @@
                     _data.writeString(path);
                     _data.writeString(oldState);
                     _data.writeString(newState);
-                    mRemote.transact(Stub.TRANSACTION_onStorageStateChanged, _data, _reply, 0);
+                    mRemote.transact(Stub.TRANSACTION_onStorageStateChanged, _data, _reply,
+                            android.os.IBinder.FLAG_ONEWAY);
+                    _reply.readException();
+                } finally {
+                    _reply.recycle();
+                    _data.recycle();
+                }
+            }
+
+            @Override
+            public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)
+                    throws RemoteException {
+                Parcel _data = Parcel.obtain();
+                Parcel _reply = Parcel.obtain();
+                try {
+                    _data.writeInterfaceToken(DESCRIPTOR);
+                    _data.writeParcelable(vol, 0);
+                    _data.writeInt(oldState);
+                    _data.writeInt(newState);
+                    mRemote.transact(Stub.TRANSACTION_onVolumeStateChanged, _data, _reply,
+                            android.os.IBinder.FLAG_ONEWAY);
                     _reply.readException();
                 } finally {
                     _reply.recycle();
@@ -154,6 +180,8 @@
         static final int TRANSACTION_onUsbMassStorageConnectionChanged = (IBinder.FIRST_CALL_TRANSACTION + 0);
 
         static final int TRANSACTION_onStorageStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 1);
+
+        static final int TRANSACTION_onVolumeStateChanged = (IBinder.FIRST_CALL_TRANSACTION + 2);
     }
 
     /**
@@ -173,4 +201,7 @@
      */
     public void onStorageStateChanged(String path, String oldState, String newState)
             throws RemoteException;
+
+    public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState)
+            throws RemoteException;
 }
diff --git a/core/java/android/os/storage/StorageEventListener.java b/core/java/android/os/storage/StorageEventListener.java
index 6c73d04..29d5494 100644
--- a/core/java/android/os/storage/StorageEventListener.java
+++ b/core/java/android/os/storage/StorageEventListener.java
@@ -21,7 +21,7 @@
  * 
  * @hide
  */
-public abstract class StorageEventListener {
+public class StorageEventListener {
     /**
      * Called when the detection state of a USB Mass Storage host has changed.
      * @param connected true if the USB mass storage is connected.
@@ -37,4 +37,7 @@
      */
     public void onStorageStateChanged(String path, String oldState, String newState) {
     }
+
+    public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+    }
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 532bf2c..5a5d8b7 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -33,15 +33,17 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import libcore.util.EmptyArray;
-
+import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 
 import java.io.File;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -64,47 +66,70 @@
 public class StorageManager {
     private static final String TAG = "StorageManager";
 
+    /** {@hide} */
+    public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
+
     private final Context mContext;
     private final ContentResolver mResolver;
 
-    /*
-     * Our internal MountService binder reference
-     */
     private final IMountService mMountService;
+    private final Looper mLooper;
+    private final AtomicInteger mNextNonce = new AtomicInteger(0);
 
-    /*
-     * The looper target for callbacks
-     */
-    private final Looper mTgtLooper;
+    private final ArrayList<StorageEventListenerDelegate> mDelegates = new ArrayList<>();
 
-    /*
-     * Target listener for binder callbacks
-     */
-    private MountServiceBinderListener mBinderListener;
+    private static class StorageEventListenerDelegate extends IMountServiceListener.Stub implements
+            Handler.Callback {
+        private static final int MSG_STORAGE_STATE_CHANGED = 1;
+        private static final int MSG_VOLUME_STATE_CHANGED = 2;
 
-    /*
-     * List of our listeners
-     */
-    private List<ListenerDelegate> mListeners = new ArrayList<ListenerDelegate>();
+        final StorageEventListener mCallback;
+        final Handler mHandler;
 
-    /*
-     * Next available nonce
-     */
-    final private AtomicInteger mNextNonce = new AtomicInteger(0);
-
-    private class MountServiceBinderListener extends IMountServiceListener.Stub {
-        public void onUsbMassStorageConnectionChanged(boolean available) {
-            final int size = mListeners.size();
-            for (int i = 0; i < size; i++) {
-                mListeners.get(i).sendShareAvailabilityChanged(available);
-            }
+        public StorageEventListenerDelegate(StorageEventListener callback, Looper looper) {
+            mCallback = callback;
+            mHandler = new Handler(looper, this);
         }
 
-        public void onStorageStateChanged(String path, String oldState, String newState) {
-            final int size = mListeners.size();
-            for (int i = 0; i < size; i++) {
-                mListeners.get(i).sendStorageStateChanged(path, oldState, newState);
+        @Override
+        public boolean handleMessage(Message msg) {
+            final SomeArgs args = (SomeArgs) msg.obj;
+            switch (msg.what) {
+                case MSG_STORAGE_STATE_CHANGED:
+                    mCallback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
+                            (String) args.arg3);
+                    args.recycle();
+                    return true;
+                case MSG_VOLUME_STATE_CHANGED:
+                    mCallback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
+                    args.recycle();
+                    return true;
             }
+            args.recycle();
+            return false;
+        }
+
+        @Override
+        public void onUsbMassStorageConnectionChanged(boolean connected) throws RemoteException {
+            // Ignored
+        }
+
+        @Override
+        public void onStorageStateChanged(String path, String oldState, String newState) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = path;
+            args.arg2 = oldState;
+            args.arg3 = newState;
+            mHandler.obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
+        }
+
+        @Override
+        public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = vol;
+            args.argi2 = oldState;
+            args.argi3 = newState;
+            mHandler.obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
         }
     }
 
@@ -159,7 +184,7 @@
         ObbListenerDelegate(OnObbStateChangeListener listener) {
             nonce = getNextNonce();
             mObbEventListenerRef = new WeakReference<OnObbStateChangeListener>(listener);
-            mHandler = new Handler(mTgtLooper) {
+            mHandler = new Handler(mLooper) {
                 @Override
                 public void handleMessage(Message msg) {
                     final OnObbStateChangeListener changeListener = getListener();
@@ -167,14 +192,7 @@
                         return;
                     }
 
-                    StorageEvent e = (StorageEvent) msg.obj;
-
-                    if (msg.what == StorageEvent.EVENT_OBB_STATE_CHANGED) {
-                        ObbStateChangedStorageEvent ev = (ObbStateChangedStorageEvent) e;
-                        changeListener.onObbStateChange(ev.path, ev.state);
-                    } else {
-                        Log.e(TAG, "Unsupported event " + msg.what);
-                    }
+                    changeListener.onObbStateChange((String) msg.obj, msg.arg1);
                 }
             };
         }
@@ -187,115 +205,7 @@
         }
 
         void sendObbStateChanged(String path, int state) {
-            ObbStateChangedStorageEvent e = new ObbStateChangedStorageEvent(path, state);
-            mHandler.sendMessage(e.getMessage());
-        }
-    }
-
-    /**
-     * Message sent during an OBB status change event.
-     */
-    private class ObbStateChangedStorageEvent extends StorageEvent {
-        public final String path;
-
-        public final int state;
-
-        public ObbStateChangedStorageEvent(String path, int state) {
-            super(EVENT_OBB_STATE_CHANGED);
-            this.path = path;
-            this.state = state;
-        }
-    }
-
-    /**
-     * Private base class for messages sent between the callback thread
-     * and the target looper handler.
-     */
-    private class StorageEvent {
-        static final int EVENT_UMS_CONNECTION_CHANGED = 1;
-        static final int EVENT_STORAGE_STATE_CHANGED = 2;
-        static final int EVENT_OBB_STATE_CHANGED = 3;
-
-        private Message mMessage;
-
-        public StorageEvent(int what) {
-            mMessage = Message.obtain();
-            mMessage.what = what;
-            mMessage.obj = this;
-        }
-
-        public Message getMessage() {
-            return mMessage;
-        }
-    }
-
-    /**
-     * Message sent on a USB mass storage connection change.
-     */
-    private class UmsConnectionChangedStorageEvent extends StorageEvent {
-        public boolean available;
-
-        public UmsConnectionChangedStorageEvent(boolean a) {
-            super(EVENT_UMS_CONNECTION_CHANGED);
-            available = a;
-        }
-    }
-
-    /**
-     * Message sent on volume state change.
-     */
-    private class StorageStateChangedStorageEvent extends StorageEvent {
-        public String path;
-        public String oldState;
-        public String newState;
-
-        public StorageStateChangedStorageEvent(String p, String oldS, String newS) {
-            super(EVENT_STORAGE_STATE_CHANGED);
-            path = p;
-            oldState = oldS;
-            newState = newS;
-        }
-    }
-
-    /**
-     * Private class containing sender and receiver code for StorageEvents.
-     */
-    private class ListenerDelegate {
-        final StorageEventListener mStorageEventListener;
-        private final Handler mHandler;
-
-        ListenerDelegate(StorageEventListener listener) {
-            mStorageEventListener = listener;
-            mHandler = new Handler(mTgtLooper) {
-                @Override
-                public void handleMessage(Message msg) {
-                    StorageEvent e = (StorageEvent) msg.obj;
-
-                    if (msg.what == StorageEvent.EVENT_UMS_CONNECTION_CHANGED) {
-                        UmsConnectionChangedStorageEvent ev = (UmsConnectionChangedStorageEvent) e;
-                        mStorageEventListener.onUsbMassStorageConnectionChanged(ev.available);
-                    } else if (msg.what == StorageEvent.EVENT_STORAGE_STATE_CHANGED) {
-                        StorageStateChangedStorageEvent ev = (StorageStateChangedStorageEvent) e;
-                        mStorageEventListener.onStorageStateChanged(ev.path, ev.oldState, ev.newState);
-                    } else {
-                        Log.e(TAG, "Unsupported event " + msg.what);
-                    }
-                }
-            };
-        }
-
-        StorageEventListener getListener() {
-            return mStorageEventListener;
-        }
-
-        void sendShareAvailabilityChanged(boolean available) {
-            UmsConnectionChangedStorageEvent e = new UmsConnectionChangedStorageEvent(available);
-            mHandler.sendMessage(e.getMessage());
-        }
-
-        void sendStorageStateChanged(String path, String oldState, String newState) {
-            StorageStateChangedStorageEvent e = new StorageStateChangedStorageEvent(path, oldState, newState);
-            mHandler.sendMessage(e.getMessage());
+            mHandler.obtainMessage(0, state, 0, path).sendToTarget();
         }
     }
 
@@ -316,14 +226,13 @@
      *
      * @hide
      */
-    public StorageManager(Context context, Looper tgtLooper) {
+    public StorageManager(Context context, Looper looper) {
         mContext = context;
         mResolver = context.getContentResolver();
-        mTgtLooper = tgtLooper;
+        mLooper = looper;
         mMountService = IMountService.Stub.asInterface(ServiceManager.getService("mount"));
         if (mMountService == null) {
-            Log.e(TAG, "Unable to connect to mount service! - is it running yet?");
-            return;
+            throw new IllegalStateException("Failed to find running mount service");
         }
     }
 
@@ -335,21 +244,15 @@
      * @hide
      */
     public void registerListener(StorageEventListener listener) {
-        if (listener == null) {
-            return;
-        }
-
-        synchronized (mListeners) {
-            if (mBinderListener == null ) {
-                try {
-                    mBinderListener = new MountServiceBinderListener();
-                    mMountService.registerListener(mBinderListener);
-                } catch (RemoteException rex) {
-                    Log.e(TAG, "Register mBinderListener failed");
-                    return;
-                }
+        synchronized (mDelegates) {
+            final StorageEventListenerDelegate delegate = new StorageEventListenerDelegate(listener,
+                    mLooper);
+            try {
+                mMountService.registerListener(delegate);
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
             }
-            mListeners.add(new ListenerDelegate(listener));
+            mDelegates.add(delegate);
         }
     }
 
@@ -361,28 +264,19 @@
      * @hide
      */
     public void unregisterListener(StorageEventListener listener) {
-        if (listener == null) {
-            return;
+        synchronized (mDelegates) {
+            for (Iterator<StorageEventListenerDelegate> i = mDelegates.iterator(); i.hasNext();) {
+                final StorageEventListenerDelegate delegate = i.next();
+                if (delegate.mCallback == listener) {
+                    try {
+                        mMountService.unregisterListener(delegate);
+                    } catch (RemoteException e) {
+                        throw e.rethrowAsRuntimeException();
+                    }
+                    i.remove();
+                }
+            }
         }
-
-        synchronized (mListeners) {
-            final int size = mListeners.size();
-            for (int i=0 ; i<size ; i++) {
-                ListenerDelegate l = mListeners.get(i);
-                if (l.getListener() == listener) {
-                    mListeners.remove(i);
-                    break;
-                }
-            }
-            if (mListeners.size() == 0 && mBinderListener != null) {
-                try {
-                    mMountService.unregisterListener(mBinderListener);
-                } catch (RemoteException rex) {
-                    Log.e(TAG, "Unregister mBinderListener failed");
-                    return;
-                }
-            }
-       }
     }
 
     /**
@@ -390,12 +284,8 @@
      *
      * @hide
      */
+    @Deprecated
     public void enableUsbMassStorage() {
-        try {
-            mMountService.setUsbMassStorageEnabled(true);
-        } catch (Exception ex) {
-            Log.e(TAG, "Failed to enable UMS", ex);
-        }
     }
 
     /**
@@ -403,12 +293,8 @@
      *
      * @hide
      */
+    @Deprecated
     public void disableUsbMassStorage() {
-        try {
-            mMountService.setUsbMassStorageEnabled(false);
-        } catch (Exception ex) {
-            Log.e(TAG, "Failed to disable UMS", ex);
-        }
     }
 
     /**
@@ -417,12 +303,8 @@
      *
      * @hide
      */
+    @Deprecated
     public boolean isUsbMassStorageConnected() {
-        try {
-            return mMountService.isUsbMassStorageConnected();
-        } catch (Exception ex) {
-            Log.e(TAG, "Failed to get UMS connection state", ex);
-        }
         return false;
     }
 
@@ -432,12 +314,8 @@
      *
      * @hide
      */
+    @Deprecated
     public boolean isUsbMassStorageEnabled() {
-        try {
-            return mMountService.isUsbMassStorageEnabled();
-        } catch (RemoteException rex) {
-            Log.e(TAG, "Failed to get UMS enable state", rex);
-        }
         return false;
     }
 
@@ -555,6 +433,114 @@
     }
 
     /** {@hide} */
+    public @NonNull List<DiskInfo> getDisks() {
+        try {
+            return Arrays.asList(mMountService.getDisks());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public @Nullable DiskInfo findDiskById(String id) {
+        Preconditions.checkNotNull(id);
+        // TODO; go directly to service to make this faster
+        for (DiskInfo disk : getDisks()) {
+            if (Objects.equals(disk.id, id)) {
+                return disk;
+            }
+        }
+        return null;
+    }
+
+    /** {@hide} */
+    public @Nullable VolumeInfo findVolumeById(String id) {
+        Preconditions.checkNotNull(id);
+        // TODO; go directly to service to make this faster
+        for (VolumeInfo vol : getVolumes()) {
+            if (Objects.equals(vol.id, id)) {
+                return vol;
+            }
+        }
+        return null;
+    }
+
+    /** {@hide} */
+    public @Nullable VolumeInfo findVolumeByUuid(String fsUuid) {
+        Preconditions.checkNotNull(fsUuid);
+        // TODO; go directly to service to make this faster
+        for (VolumeInfo vol : getVolumes()) {
+            if (Objects.equals(vol.fsUuid, fsUuid)) {
+                return vol;
+            }
+        }
+        return null;
+    }
+
+    /** {@hide} */
+    public @NonNull List<VolumeInfo> getVolumes() {
+        try {
+            return Arrays.asList(mMountService.getVolumes());
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void mount(String volId) {
+        try {
+            mMountService.mount(volId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void unmount(String volId) {
+        try {
+            mMountService.unmount(volId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void format(String volId) {
+        try {
+            mMountService.format(volId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void partitionPublic(String diskId) {
+        try {
+            mMountService.partitionPublic(diskId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void partitionPrivate(String diskId) {
+        try {
+            mMountService.partitionPrivate(diskId);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
+    public void partitionMixed(String diskId, int ratio) {
+        try {
+            mMountService.partitionMixed(diskId, ratio);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+    }
+
+    /** {@hide} */
     public @Nullable StorageVolume getStorageVolume(File file) {
         return getStorageVolume(getVolumeList(), file);
     }
@@ -597,16 +583,9 @@
         }
     }
 
-    /**
-     * Returns list of all mountable volumes.
-     * @hide
-     */
+    /** {@hide} */
     public @NonNull StorageVolume[] getVolumeList() {
-        try {
-            return mMountService.getVolumeList(mContext.getUserId());
-        } catch (RemoteException e) {
-            throw e.rethrowAsRuntimeException();
-        }
+        return getVolumeList(mContext.getUserId());
     }
 
     /** {@hide} */
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 0c391ca..d66e228 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -23,13 +23,17 @@
 import android.os.UserHandle;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
 
 import java.io.CharArrayWriter;
 import java.io.File;
 
 /**
- * Description of a storage volume and its capabilities, including the
- * filesystem path where it may be mounted.
+ * Information about a storage volume that may be mounted. This is a legacy
+ * specialization of {@link VolumeInfo} which describes the volume for a
+ * specific user.
+ * <p>
+ * This class may be deprecated in the future.
  *
  * @hide
  */
@@ -37,21 +41,16 @@
 
     private final String mId;
     private final int mStorageId;
-
     private final File mPath;
-    private final int mDescriptionId;
+    private final String mDescription;
     private final boolean mPrimary;
     private final boolean mRemovable;
     private final boolean mEmulated;
     private final long mMtpReserveSize;
     private final boolean mAllowMassStorage;
-    /** Maximum file size for the storage, or zero for no limit */
     private final long mMaxFileSize;
-    /** When set, indicates exclusive ownership of this volume */
     private final UserHandle mOwner;
-
-    private final String mUuid;
-    private final String mUserLabel;
+    private final String mFsUuid;
     private final String mState;
 
     // StorageVolume extra for ACTION_MEDIA_REMOVED, ACTION_MEDIA_UNMOUNTED, ACTION_MEDIA_CHECKING,
@@ -59,30 +58,29 @@
     // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
     public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
 
-    public StorageVolume(String id, int storageId, File path, int descriptionId, boolean primary,
+    public StorageVolume(String id, int storageId, File path, String description, boolean primary,
             boolean removable, boolean emulated, long mtpReserveSize, boolean allowMassStorage,
-            long maxFileSize, UserHandle owner, String uuid, String userLabel, String state) {
-        mId = id;
+            long maxFileSize, UserHandle owner, String fsUuid, String state) {
+        mId = Preconditions.checkNotNull(id);
         mStorageId = storageId;
-        mPath = path;
-        mDescriptionId = descriptionId;
+        mPath = Preconditions.checkNotNull(path);
+        mDescription = Preconditions.checkNotNull(description);
         mPrimary = primary;
         mRemovable = removable;
         mEmulated = emulated;
         mMtpReserveSize = mtpReserveSize;
         mAllowMassStorage = allowMassStorage;
         mMaxFileSize = maxFileSize;
-        mOwner = owner;
-        mUuid = uuid;
-        mUserLabel = userLabel;
-        mState = state;
+        mOwner = Preconditions.checkNotNull(owner);
+        mFsUuid = fsUuid;
+        mState = Preconditions.checkNotNull(state);
     }
 
     private StorageVolume(Parcel in) {
         mId = in.readString();
         mStorageId = in.readInt();
         mPath = new File(in.readString());
-        mDescriptionId = in.readInt();
+        mDescription = in.readString();
         mPrimary = in.readInt() != 0;
         mRemovable = in.readInt() != 0;
         mEmulated = in.readInt() != 0;
@@ -90,8 +88,7 @@
         mAllowMassStorage = in.readInt() != 0;
         mMaxFileSize = in.readLong();
         mOwner = in.readParcelable(null);
-        mUuid = in.readString();
-        mUserLabel = in.readString();
+        mFsUuid = in.readString();
         mState = in.readString();
     }
 
@@ -118,11 +115,7 @@
      * @return the volume description
      */
     public String getDescription(Context context) {
-        return context.getResources().getString(mDescriptionId);
-    }
-
-    public int getDescriptionId() {
-        return mDescriptionId;
+        return mDescription;
     }
 
     public boolean isPrimary() {
@@ -196,7 +189,7 @@
     }
 
     public String getUuid() {
-        return mUuid;
+        return mFsUuid;
     }
 
     /**
@@ -204,18 +197,18 @@
      * parse or UUID is unknown.
      */
     public int getFatVolumeId() {
-        if (mUuid == null || mUuid.length() != 9) {
+        if (mFsUuid == null || mFsUuid.length() != 9) {
             return -1;
         }
         try {
-            return (int)Long.parseLong(mUuid.replace("-", ""), 16);
+            return (int) Long.parseLong(mFsUuid.replace("-", ""), 16);
         } catch (NumberFormatException e) {
             return -1;
         }
     }
 
     public String getUserLabel() {
-        return mUserLabel;
+        return mDescription;
     }
 
     public String getState() {
@@ -249,7 +242,7 @@
         pw.printPair("mId", mId);
         pw.printPair("mStorageId", mStorageId);
         pw.printPair("mPath", mPath);
-        pw.printPair("mDescriptionId", mDescriptionId);
+        pw.printPair("mDescription", mDescription);
         pw.printPair("mPrimary", mPrimary);
         pw.printPair("mRemovable", mRemovable);
         pw.printPair("mEmulated", mEmulated);
@@ -257,8 +250,7 @@
         pw.printPair("mAllowMassStorage", mAllowMassStorage);
         pw.printPair("mMaxFileSize", mMaxFileSize);
         pw.printPair("mOwner", mOwner);
-        pw.printPair("mUuid", mUuid);
-        pw.printPair("mUserLabel", mUserLabel);
+        pw.printPair("mFsUuid", mFsUuid);
         pw.printPair("mState", mState);
         pw.decreaseIndent();
     }
@@ -285,7 +277,7 @@
         parcel.writeString(mId);
         parcel.writeInt(mStorageId);
         parcel.writeString(mPath.toString());
-        parcel.writeInt(mDescriptionId);
+        parcel.writeString(mDescription);
         parcel.writeInt(mPrimary ? 1 : 0);
         parcel.writeInt(mRemovable ? 1 : 0);
         parcel.writeInt(mEmulated ? 1 : 0);
@@ -293,8 +285,7 @@
         parcel.writeInt(mAllowMassStorage ? 1 : 0);
         parcel.writeLong(mMaxFileSize);
         parcel.writeParcelable(mOwner, flags);
-        parcel.writeString(mUuid);
-        parcel.writeString(mUserLabel);
+        parcel.writeString(mFsUuid);
         parcel.writeString(mState);
     }
 }
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/os/storage/VolumeInfo.aidl
similarity index 89%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to core/java/android/os/storage/VolumeInfo.aidl
index c9fd989..32d12da 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/core/java/android/os/storage/VolumeInfo.aidl
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package android.os.storage;
+
+parcelable VolumeInfo;
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
new file mode 100644
index 0000000..2dc0361
--- /dev/null
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os.storage;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.mtp.MtpStorage;
+import android.os.Environment;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.DebugUtils;
+import android.util.SparseArray;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+
+import java.io.CharArrayWriter;
+import java.io.File;
+
+/**
+ * Information about a storage volume that may be mounted. A volume may be a
+ * partition on a physical {@link DiskInfo}, an emulated volume above some other
+ * storage medium, or a standalone container like an ASEC or OBB.
+ *
+ * @hide
+ */
+public class VolumeInfo implements Parcelable {
+    /** Real volume representing internal emulated storage */
+    public static final String ID_EMULATED_INTERNAL = "emulated";
+
+    public static final int TYPE_PUBLIC = 0;
+    public static final int TYPE_PRIVATE = 1;
+    public static final int TYPE_EMULATED = 2;
+    public static final int TYPE_ASEC = 3;
+    public static final int TYPE_OBB = 4;
+
+    public static final int STATE_UNMOUNTED = 0;
+    public static final int STATE_MOUNTING = 1;
+    public static final int STATE_MOUNTED = 2;
+    public static final int STATE_FORMATTING = 3;
+    public static final int STATE_UNMOUNTING = 4;
+    public static final int STATE_UNMOUNTABLE = 5;
+
+    public static final int FLAG_PRIMARY = 1 << 0;
+    public static final int FLAG_VISIBLE = 1 << 1;
+
+    private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
+    private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
+
+    static {
+        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
+        sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING);
+        sStateToEnvironment.put(VolumeInfo.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
+        sStateToEnvironment.put(VolumeInfo.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
+        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
+        sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTABLE, Environment.MEDIA_UNMOUNTABLE);
+
+        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
+        sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
+        sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
+        sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
+        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTABLE, Intent.ACTION_MEDIA_UNMOUNTABLE);
+    }
+
+    /** vold state */
+    public final String id;
+    public final int type;
+    public int flags = 0;
+    public int userId = -1;
+    public int state = STATE_UNMOUNTED;
+    public String fsType;
+    public String fsUuid;
+    public String fsLabel;
+    public String path;
+
+    /** Framework state */
+    public final int mtpIndex;
+    public String nickname;
+
+    public DiskInfo disk;
+
+    public VolumeInfo(String id, int type, int mtpIndex) {
+        this.id = Preconditions.checkNotNull(id);
+        this.type = type;
+        this.mtpIndex = mtpIndex;
+    }
+
+    public VolumeInfo(Parcel parcel) {
+        id = parcel.readString();
+        type = parcel.readInt();
+        flags = parcel.readInt();
+        userId = parcel.readInt();
+        state = parcel.readInt();
+        fsType = parcel.readString();
+        fsUuid = parcel.readString();
+        fsLabel = parcel.readString();
+        path = parcel.readString();
+        mtpIndex = parcel.readInt();
+        nickname = parcel.readString();
+    }
+
+    public static @NonNull String getEnvironmentForState(int state) {
+        final String envState = sStateToEnvironment.get(state);
+        if (envState != null) {
+            return envState;
+        } else {
+            return Environment.MEDIA_UNKNOWN;
+        }
+    }
+
+    public static @Nullable String getBroadcastForEnvironment(String envState) {
+        return sEnvironmentToBroadcast.get(envState);
+    }
+
+    public static @Nullable String getBroadcastForState(int state) {
+        return getBroadcastForEnvironment(getEnvironmentForState(state));
+    }
+
+    public String getDescription(Context context) {
+        if (ID_EMULATED_INTERNAL.equals(id)) {
+            return context.getString(com.android.internal.R.string.storage_internal);
+        } else if (!TextUtils.isEmpty(nickname)) {
+            return nickname;
+        } else if (!TextUtils.isEmpty(fsLabel)) {
+            return fsLabel;
+        } else {
+            return null;
+        }
+    }
+
+    public boolean isPrimary() {
+        return (flags & FLAG_PRIMARY) != 0;
+    }
+
+    public boolean isVisible() {
+        return (flags & FLAG_VISIBLE) != 0;
+    }
+
+    public boolean isVisibleToUser(int userId) {
+        if (type == TYPE_PUBLIC && userId == this.userId) {
+            return isVisible();
+        } else if (type == TYPE_EMULATED) {
+            return isVisible();
+        } else {
+            return false;
+        }
+    }
+
+    public File getPathForUser(int userId) {
+        if (path == null) {
+            return null;
+        } else if (type == TYPE_PUBLIC && userId == this.userId) {
+            return new File(path);
+        } else if (type == TYPE_EMULATED) {
+            return new File(path, Integer.toString(userId));
+        } else {
+            return null;
+        }
+    }
+
+    public StorageVolume buildStorageVolume(Context context, int userId) {
+        final boolean removable;
+        final boolean emulated;
+        final boolean allowMassStorage = false;
+        final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
+        final String envState = getEnvironmentForState(state);
+
+        File userPath = getPathForUser(userId);
+        if (userPath == null) {
+            userPath = new File("/dev/null");
+        }
+
+        String description = getDescription(context);
+        if (description == null) {
+            description = context.getString(android.R.string.unknownName);
+        }
+
+        long mtpReserveSize = 0;
+        long maxFileSize = 0;
+
+        if (type == TYPE_EMULATED) {
+            emulated = true;
+            mtpReserveSize = StorageManager.from(context).getStorageLowBytes(userPath);
+
+            if (ID_EMULATED_INTERNAL.equals(id)) {
+                removable = false;
+            } else {
+                removable = true;
+            }
+
+        } else if (type == TYPE_PUBLIC) {
+            emulated = false;
+            removable = true;
+
+            if ("vfat".equals(fsType)) {
+                maxFileSize = 4294967295L;
+            }
+
+        } else {
+            throw new IllegalStateException("Unexpected volume type " + type);
+        }
+
+        return new StorageVolume(id, mtpStorageId, userPath, description, isPrimary(), removable,
+                emulated, mtpReserveSize, allowMassStorage, maxFileSize, new UserHandle(userId),
+                fsUuid, envState);
+    }
+
+    @Override
+    public String toString() {
+        final CharArrayWriter writer = new CharArrayWriter();
+        dump(new IndentingPrintWriter(writer, "    ", 80));
+        return writer.toString();
+    }
+
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("VolumeInfo:");
+        pw.increaseIndent();
+        pw.printPair("id", id);
+        pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
+        pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
+        pw.printPair("userId", userId);
+        pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
+        pw.println();
+        pw.printPair("fsType", fsType);
+        pw.printPair("fsUuid", fsUuid);
+        pw.printPair("fsLabel", fsLabel);
+        pw.println();
+        pw.printPair("path", path);
+        pw.printPair("mtpIndex", mtpIndex);
+        pw.decreaseIndent();
+        pw.println();
+    }
+
+    @Override
+    public VolumeInfo clone() {
+        final Parcel temp = Parcel.obtain();
+        try {
+            writeToParcel(temp, 0);
+            temp.setDataPosition(0);
+            return CREATOR.createFromParcel(temp);
+        } finally {
+            temp.recycle();
+        }
+    }
+
+    public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() {
+        @Override
+        public VolumeInfo createFromParcel(Parcel in) {
+            return new VolumeInfo(in);
+        }
+
+        @Override
+        public VolumeInfo[] newArray(int size) {
+            return new VolumeInfo[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeString(id);
+        parcel.writeInt(type);
+        parcel.writeInt(flags);
+        parcel.writeInt(userId);
+        parcel.writeInt(state);
+        parcel.writeString(fsType);
+        parcel.writeString(fsUuid);
+        parcel.writeString(fsLabel);
+        parcel.writeString(path);
+        parcel.writeInt(mtpIndex);
+        parcel.writeString(nickname);
+    }
+}
diff --git a/core/java/android/provider/AlarmClock.java b/core/java/android/provider/AlarmClock.java
index 724d76d..25a35e1 100644
--- a/core/java/android/provider/AlarmClock.java
+++ b/core/java/android/provider/AlarmClock.java
@@ -43,8 +43,14 @@
      * should remove this alarm after it has been dismissed. If an identical alarm exists matching
      * all parameters, the implementation may re-use it instead of creating a new one (in this case,
      * the alarm should not be removed after dismissal).
-     *
+     * </p><p>
      * This action always enables the alarm.
+     * </p><p>
+     * This activity could also be started in Voice Interaction mode. The activity should check
+     * {@link android.app.Activity#isVoiceInteraction}, and if true, the implementation should
+     * report a deeplink of the created/enabled alarm using
+     * {@link android.app.VoiceInteractor.CompleteVoiceRequest}. This allows follow-on voice actions
+     * such as {@link #ACTION_VOICE_CANCEL_ALARM} to cancel the alarm that was just enabled.
      * </p>
      * <h3>Request parameters</h3>
      * <ul>
@@ -63,6 +69,48 @@
     public static final String ACTION_SET_ALARM = "android.intent.action.SET_ALARM";
 
     /**
+     * Voice Activity Action: Cancel an alarm.
+     * Requires: The activity must check {@link android.app.Activity#isVoiceInteraction}, i.e. be
+     * started in Voice Interaction mode.
+     * <p>
+     * Cancels the specified alarm by voice. To cancel means to disable, but not delete, the alarm.
+     * See {@link #ACTION_VOICE_DELETE_ALARM} to delete an alarm by voice.
+     * </p><p>
+     * The alarm to cancel can be specified or searched for in one of the following ways:
+     * <ol>
+     * <li>The Intent's data URI specifies a deeplink to the alarm.
+     * <li>If the Intent's data URI is unspecified, then the extra {@link #EXTRA_ALARM_SEARCH_MODE} is
+     * required to determine how to search for the alarm.
+     *
+     * @see #ACTION_VOICE_DELETE_ALARM
+     * @see #EXTRA_ALARM_SEARCH_MODE
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VOICE_CANCEL_ALARM =
+            "android.intent.action.VOICE_CANCEL_ALARM";
+
+    /**
+     * Voice Activity Action: Delete an alarm.
+     * Requires: The activity must check {@link android.app.Activity#isVoiceInteraction}, i.e. be
+     * started in Voice Interaction mode.
+     * <p>
+     * Deletes the specified alarm by voice.
+     * See {@link #ACTION_VOICE_CANCEL_ALARM} to cancel (disable) an alarm by voice.
+     * </p><p>
+     * The alarm to delete can be specified or searched for in one of the following ways:
+     * <ol>
+     * <li>The Intent's data URI specifies a deeplink to the alarm.
+     * <li>If the Intent's data URI is unspecified, then the extra {@link #EXTRA_ALARM_SEARCH_MODE} is
+     * required to determine how to search for the alarm.
+     *
+     * @see #ACTION_VOICE_CANCEL_ALARM
+     * @see #EXTRA_ALARM_SEARCH_MODE
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VOICE_DELETE_ALARM =
+            "android.intent.action.VOICE_DELETE_ALARM";
+
+    /**
      * Activity Action: Set a timer.
      * <p>
      * Activates an existing timer or creates a new one.
@@ -99,6 +147,100 @@
      public static final String ACTION_SHOW_ALARMS = "android.intent.action.SHOW_ALARMS";
 
     /**
+     * Bundle extra: Specify the type of search mode to look up an alarm.
+     * <p>
+     * Used by {@link #ACTION_VOICE_CANCEL_ALARM} and {@link #ACTION_VOICE_DELETE_ALARM} to identify
+     * the alarm(s) to cancel or delete, respectively.
+     * </p><p>
+     * This extra is only required when the alarm is not already identified by a deeplink as
+     * specified in the Intent's data URI.
+     * </p><p>
+     * The value of this extra is a {@link String}, restricted to the following set of supported
+     * search modes:
+     * <ul>
+     * <li><i>Time</i> - {@link #ALARM_SEARCH_MODE_TIME}: Selects the alarm that is most
+     * closely matched by the search parameters {@link #EXTRA_HOUR}, {@link #EXTRA_MINUTES},
+     * {@link #EXTRA_IS_PM}.
+     * <li><i>Next alarm</i> - {@link #ALARM_SEARCH_MODE_NEXT}: Selects the alarm that will
+     * ring next, or the alarm that is currently ringing, if any.
+     * <li><i>All alarms</i> - {@link #ALARM_SEARCH_MODE_ALL}: Selects all alarms.
+     * <li><i>None</i> - {@link #ALARM_SEARCH_MODE_NONE}: No search mode specified. The
+     * implementation should ask the user to select a search mode using
+     * {@link android.app.VoiceInteractor.PickOptionRequest} and proceed with a voice flow to
+     * identify the alarm.
+     * </ul>
+     * </ol>
+     *
+     * @see #ALARM_SEARCH_MODE_TIME
+     * @see #ALARM_SEARCH_MODE_NEXT
+     * @see #ALARM_SEARCH_MODE_ALL
+     * @see #ALARM_SEARCH_MODE_NONE
+     * @see #ACTION_VOICE_CANCEL_ALARM
+     * @see #ACTION_VOICE_DELETE_ALARM
+     */
+    public static final String EXTRA_ALARM_SEARCH_MODE =
+        "android.intent.extra.alarm.ALARM_SEARCH_MODE";
+
+    /**
+     * Search for the alarm that is most closely matched by the search parameters
+     * {@link #EXTRA_HOUR}, {@link #EXTRA_MINUTES}, {@link #EXTRA_IS_PM}.
+     * In this search mode, at least one of these additional extras are required.
+     * <ul>
+     * <li>{@link #EXTRA_HOUR} - The hour to search for the alarm.
+     * <li>{@link #EXTRA_MINUTES} - The minute to search for the alarm.
+     * <li>{@link #EXTRA_IS_PM} - Whether the hour is AM or PM.
+     * </ul>
+     *
+     * @see #EXTRA_ALARM_SEARCH_MODE
+     */
+    public static final String ALARM_SEARCH_MODE_TIME = "time";
+
+    /**
+     * Selects the alarm that will ring next, or the alarm that is currently ringing, if any.
+     *
+     * @see #EXTRA_ALARM_SEARCH_MODE
+     */
+    public static final String ALARM_SEARCH_MODE_NEXT = "next";
+
+    /**
+     * Selects all alarms.
+     *
+     * @see #EXTRA_ALARM_SEARCH_MODE
+     */
+    public static final String ALARM_SEARCH_MODE_ALL = "all";
+
+    /**
+     * No search mode specified. The implementation should ask the user to select a search mode
+     * using {@link android.app.VoiceInteractor.PickOptionRequest} and proceed with a voice flow to
+     * identify the alarm.
+     *
+     * @see #EXTRA_ALARM_SEARCH_MODE
+     */
+    public static final String ALARM_SEARCH_MODE_NONE = "none";
+
+    /**
+     * Bundle extra: The AM/PM of the alarm.
+     * <p>
+     * Used by {@link #ACTION_VOICE_CANCEL_ALARM} and {@link #ACTION_VOICE_DELETE_ALARM}.
+     * </p><p>
+     * This extra is optional and only used when {@link #EXTRA_ALARM_SEARCH_MODE} is set to
+     * {@link #ALARM_SEARCH_MODE_TIME}. In this search mode, the {@link #EXTRA_IS_PM} is
+     * used together with {@link #EXTRA_HOUR} and {@link #EXTRA_MINUTES}. The implementation should
+     * look up the alarm that is most closely matched by these search parameters.
+     * If {@link #EXTRA_IS_PM} is missing, then the AM/PM of the specified {@link #EXTRA_HOUR} is
+     * ambiguous and the implementation should ask for clarification from the user.
+     * </p><p>
+     * The value is a {@link Boolean}, where false=AM and true=PM.
+     * </p>
+     *
+     * @see #ACTION_VOICE_CANCEL_ALARM
+     * @see #ACTION_VOICE_DELETE_ALARM
+     * @see #EXTRA_HOUR
+     * @see #EXTRA_MINUTES
+     */
+    public static final String EXTRA_IS_PM = "android.intent.extra.alarm.IS_PM";
+
+    /**
      * Bundle extra: Weekdays for repeating alarm.
      * <p>
      * Used by {@link #ACTION_SET_ALARM}.
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 6517f35..7d57233 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -454,7 +454,6 @@
                 long start, int duration, Long dataUsage, boolean addForAllUsers) {
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
-            boolean isHidden = false;
 
             TelecomManager tm = null;
             try {
@@ -469,12 +468,6 @@
                     if (address != null) {
                         accountAddress = address.getSchemeSpecificPart();
                     }
-                } else {
-                    // We could not find the account through telecom. For call log entries that
-                    // are added with a phone account which is not registered, we automatically
-                    // mark them as hidden. They are unhidden once the account is registered.
-                    Log.i(LOG_TAG, "Marking call log entry as hidden.");
-                    isHidden = true;
                 }
             }
 
@@ -520,7 +513,6 @@
             values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
             values.put(PHONE_ACCOUNT_ID, accountId);
             values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
-            values.put(PHONE_ACCOUNT_HIDDEN, Integer.valueOf(isHidden ? 1 : 0));
             values.put(NEW, Integer.valueOf(1));
 
             if (callType == MISSED_TYPE) {
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 5afbd6d..7565654b 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -226,6 +226,35 @@
     public static final String INTENT_ACTION_STILL_IMAGE_CAMERA = "android.media.action.STILL_IMAGE_CAMERA";
 
     /**
+     * The name of the Intent action used to indicate that a camera launch might be imminent. This
+     * broadcast should be targeted to the package that is receiving
+     * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA} or
+     * {@link #INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE}, depending on the context. If such
+     * intent would launch the resolver activity, this broadcast should not be sent at all.
+     * <p>
+     * A receiver of this broadcast should do the absolute minimum amount of work to initialize the
+     * camera in order to reduce startup time in likely case that shortly after an actual camera
+     * launch intent would be sent.
+     * <p>
+     * In case the actual intent will not be fired, the target package will receive
+     * {@link #ACTION_STILL_IMAGE_CAMERA_COOLDOWN}. However, it is recommended that the receiver
+     * also implements a timeout to close the camera after receiving this intent, as there is no
+     * guarantee that {@link #ACTION_STILL_IMAGE_CAMERA_COOLDOWN} will be delivered.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_STILL_IMAGE_CAMERA_PREWARM = "android.media.action.STILL_IMAGE_CAMERA_PREWARM";
+
+    /**
+     * The name of the Intent action used to indicate that an imminent camera launch has been
+     * cancelled by the user. This broadcast should be targeted to the package that has received
+     * {@link #ACTION_STILL_IMAGE_CAMERA_PREWARM}.
+     * <p>
+     * A receiver of this broadcast should close the camera immediately.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_STILL_IMAGE_CAMERA_COOLDOWN = "android.media.action.STILL_IMAGE_CAMERA_COOLDOWN";
+
+    /**
      * The name of the Intent action used to launch a camera in still image mode
      * for use when the device is secured (e.g. with a pin, password, pattern,
      * or face unlock). Applications responding to this intent must not expose
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 8e5d245..3087e1d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -138,7 +138,7 @@
             "android.settings.AIRPLANE_MODE_SETTINGS";
 
     /**
-     * Activity Action: Modify Airplane mode settings using the users voice.
+     * Activity Action: Modify Airplane mode settings using a voice command.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
      * <p>
@@ -146,15 +146,13 @@
      * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity
      * startVoiceActivity}.
      * <p>
-     * To tell which state airplane mode should be set to, add the
-     * {@link #EXTRA_AIRPLANE_MODE_ENABLED} extra to this Intent with the state specified.
-     * If there is no extra in this Intent, no changes will be made.
-     * <p>
-     * The activity should verify that
+     * Note: The activity implementing this intent MUST verify that
      * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction} returns true before
      * modifying the setting.
      * <p>
-     * Input: Nothing.
+     * Input: To tell which state airplane mode should be set to, add the
+     * {@link #EXTRA_AIRPLANE_MODE_ENABLED} extra to this Intent with the state specified.
+     * If the extra is not included, no changes will be made.
      * <p>
      * Output: Nothing.
      */
@@ -839,6 +837,58 @@
     public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS";
 
     /**
+     * Activity Action: Show Zen Mode priority configuration settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ZEN_MODE_PRIORITY_SETTINGS
+            = "android.settings.ZEN_MODE_PRIORITY_SETTINGS";
+
+    /**
+     * Activity Action: Show Zen Mode automation configuration settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ZEN_MODE_AUTOMATION_SETTINGS
+            = "android.settings.ZEN_MODE_AUTOMATION_SETTINGS";
+
+    /**
+     * Activity Action: Modify do not disturb mode settings.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+     * <p>
+     * This intent MUST be started using
+     * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity
+     * startVoiceActivity}.
+     * <p>
+     * Note: The Activity implementing this intent MUST verify that
+     * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction}.
+     * returns true before modifying the setting.
+     * <p>
+     * Input: The optional {@link #EXTRA_DO_NOT_DISTURB_MODE_MINUTES} extra can be used to indicate
+     * how long the user wishes to avoid interruptions for. The optional
+     * {@link #EXTRA_DO_NOT_DISTURB_MODE_ENABLED} extra can be to indicate if the user is
+     * enabling or disabling do not disturb mode. If either extra is not included, the
+     * user maybe asked to provide the value.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE =
+            "android.settings.VOICE_CONTROL_DO_NOT_DISTURB_MODE";
+
+    /**
+     * Activity Action: Show Zen Mode schedule rule configuration settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ZEN_MODE_SCHEDULE_RULE_SETTINGS
+            = "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS";
+
+    /**
      * Activity Action: Show the regulatory information screen for the device.
      * <p>
      * In some cases, a matching Activity may not exist, so ensure you safeguard
@@ -885,6 +935,29 @@
             = "android.settings.BATTERY_SAVER_SETTINGS";
 
     /**
+     * Activity Action: Modify Battery Saver mode setting using a voice command.
+     * <p>
+     * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+     * <p>
+     * This intent MUST be started using
+     * {@link android.service.voice.VoiceInteractionSession#startVoiceActivity
+     * startVoiceActivity}.
+     * <p>
+     * Note: The activity implementing this intent MUST verify that
+     * {@link android.app.Activity#isVoiceInteraction isVoiceInteraction} returns true before
+     * modifying the setting.
+     * <p>
+     * Input: To tell which state batter saver mode should be set to, add the
+     * {@link #EXTRA_BATTERY_SAVER_MODE_ENABLED} extra to this Intent with the state specified.
+     * If the extra is not included, no changes will be made.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE =
+            "android.settings.VOICE_CONTROL_BATTERY_SAVER_MODE";
+
+    /**
      * Activity Action: Show Home selection settings. If there are multiple activities
      * that can satisfy the {@link Intent#CATEGORY_HOME} intent, this screen allows you
      * to pick your preferred activity.
@@ -998,10 +1071,37 @@
      * Activity Extra: Enable or disable Airplane Mode.
      * <p>
      * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_AIRPLANE_MODE}
-     * intent as a boolean.
+     * intent as a boolean to indicate if it should be enabled.
      */
     public static final String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
 
+    /**
+     * Activity Extra: Enable or disable Battery saver mode.
+     * <p>
+     * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_BATTERY_SAVER_MODE}
+     * intent as a boolean to indicate if it should be enabled.
+     */
+    public static final String EXTRA_BATTERY_SAVER_MODE_ENABLED =
+            "android.settings.extra.battery_saver_mode_enabled";
+
+    /**
+     * Activity Extra: Enable or disable Do Not Disturb mode.
+     * <p>
+     * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE}
+     * intent as a boolean to indicate if it should be enabled.
+     */
+    public static final String EXTRA_DO_NOT_DISTURB_MODE_ENABLED =
+            "android.settings.extra.do_not_disturb_mode_enabled";
+
+    /**
+     * Activity Extra: How many minutes to enable do not disturb mode for.
+     * <p>
+     * This can be passed as an extra field to the {@link #ACTION_VOICE_CONTROL_DO_NOT_DISTURB_MODE}
+     * intent to indicate how long do not disturb mode should be enabled for.
+     */
+    public static final String EXTRA_DO_NOT_DISTURB_MODE_MINUTES =
+            "android.settings.extra.do_not_disturb_mode_minutes";
+
     private static final String JID_RESOURCE_PREFIX = "android";
 
     public static final String AUTHORITY = "settings";
@@ -3026,7 +3126,7 @@
         };
 
         /**
-         * These are all pulbic system settings
+         * These are all public system settings
          *
          * @hide
          */
@@ -3126,7 +3226,7 @@
         }
 
         /**
-         * These are all pulbic system settings
+         * These are all public system settings
          *
          * @hide
          */
@@ -5363,6 +5463,13 @@
         public static final String SLEEP_TIMEOUT = "sleep_timeout";
 
         /**
+         * Duration in milliseconds that an app should be inactive before it is considered idle.
+         * <p/>Type: Long
+         * @hide
+         */
+        public static final String APP_IDLE_DURATION = "app_idle_duration";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -5425,6 +5532,7 @@
          * since the managed profile doesn't get to change them.
          */
         private static final Set<String> CLONE_TO_MANAGED_PROFILE = new ArraySet<>();
+
         static {
             CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_ENABLED);
             CLONE_TO_MANAGED_PROFILE.add(ALLOW_MOCK_LOCATION);
@@ -6375,6 +6483,14 @@
                 "wifi_scan_always_enabled";
 
        /**
+        * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
+        * connectivity.
+        * @hide
+        */
+       public static final String BLE_SCAN_ALWAYS_AVAILABLE =
+               "ble_scan_always_enabled";
+
+       /**
         * Used to save the Wifi_ON state prior to tethering.
         * This state will be checked to restore Wifi after
         * the user turns off tethering.
@@ -7102,13 +7218,27 @@
         /** @hide */ public static final int ZEN_MODE_OFF = 0;
         /** @hide */ public static final int ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1;
         /** @hide */ public static final int ZEN_MODE_NO_INTERRUPTIONS = 2;
+        /** @hide */ public static final int ZEN_MODE_ALARMS = 3;
 
         /** @hide */ public static String zenModeToString(int mode) {
             if (mode == ZEN_MODE_IMPORTANT_INTERRUPTIONS) return "ZEN_MODE_IMPORTANT_INTERRUPTIONS";
+            if (mode == ZEN_MODE_ALARMS) return "ZEN_MODE_ALARMS";
             if (mode == ZEN_MODE_NO_INTERRUPTIONS) return "ZEN_MODE_NO_INTERRUPTIONS";
             return "ZEN_MODE_OFF";
         }
 
+        /** @hide */ public static boolean isValidZenMode(int value) {
+            switch (value) {
+                case Global.ZEN_MODE_OFF:
+                case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                case Global.ZEN_MODE_ALARMS:
+                case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+
         /**
          * Opaque value, changes when persisted zen mode configuration changes.
          *
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 0da4fd5..4712f97 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SystemApi;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
@@ -254,11 +255,14 @@
          * @param context The context of the app doing the inserting
          * @param voicemail Data to be inserted
          * @return {@link Uri} of the newly inserted {@link Voicemail}
+         *
+         * @hide
          */
+        @SystemApi
         public static Uri insert(Context context, Voicemail voicemail) {
             ContentResolver contentResolver = context.getContentResolver();
             ContentValues contentValues = getContentValues(voicemail);
-            return contentResolver.insert(Voicemails.CONTENT_URI, contentValues);
+            return contentResolver.insert(buildSourceUri(context.getPackageName()), contentValues);
         }
 
         /**
@@ -267,13 +271,16 @@
          * @param context The context of the app doing the inserting
          * @param voicemails Data to be inserted
          * @return the number of voicemails inserted
+         *
+         * @hide
          */
+        @SystemApi
         public static int insert(Context context, List<Voicemail> voicemails) {
             ContentResolver contentResolver = context.getContentResolver();
             int count = voicemails.size();
             for (int i = 0; i < count; i++) {
                 ContentValues contentValues = getContentValues(voicemails.get(i));
-                contentResolver.insert(Voicemails.CONTENT_URI, contentValues);
+                contentResolver.insert(buildSourceUri(context.getPackageName()), contentValues);
             }
             return count;
         }
@@ -283,7 +290,10 @@
          * package. By default, a package only has permission to delete voicemails it inserted.
          *
          * @return the number of voicemails deleted
+         *
+         * @hide
          */
+        @SystemApi
         public static int deleteAll(Context context) {
             return context.getContentResolver().delete(
                     buildSourceUri(context.getPackageName()), "", new String[0]);
@@ -439,7 +449,10 @@
          * @param configurationState See {@link Status#CONFIGURATION_STATE}
          * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
          * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
+         *
+         * @hide
          */
+        @SystemApi
         public static void setStatus(Context context, PhoneAccountHandle accountHandle,
                 int configurationState, int dataChannelState, int notificationChannelState) {
             ContentResolver contentResolver = context.getContentResolver();
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index c2ebbc6..ea53c0d 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -47,21 +47,17 @@
     public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
     public static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
     public static final int KM_TAG_KEY_SIZE = KM_INT | 3;
-    public static final int KM_TAG_BLOCK_MODE = KM_ENUM | 4;
-    public static final int KM_TAG_DIGEST = KM_ENUM | 5;
-    public static final int KM_TAG_MAC_LENGTH = KM_INT | 6;
-    public static final int KM_TAG_PADDING = KM_ENUM | 7;
-    public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 8;
-    public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 9;
+    public static final int KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4;
+    public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
+    public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
+    public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 7;
+    public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 8;
 
     public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
     public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
     public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
 
     public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_LONG | 200;
-    public static final int KM_TAG_DSA_GENERATOR = KM_BIGNUM | 201;
-    public static final int KM_TAG_DSA_P = KM_BIGNUM | 202;
-    public static final int KM_TAG_DSA_Q = KM_BIGNUM | 203;
     public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
     public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
     public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
@@ -88,43 +84,21 @@
     public static final int KM_TAG_NONCE = KM_BYTES | 1001;
     public static final int KM_TAG_CHUNK_LENGTH = KM_INT | 1002;
     public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1003;
+    public static final int KM_TAG_MAC_LENGTH = KM_INT | 1004;
 
     // Algorithm values.
     public static final int KM_ALGORITHM_RSA = 1;
-    public static final int KM_ALGORITHM_DSA = 2;
-    public static final int KM_ALGORITHM_ECDSA = 3;
-    public static final int KM_ALGORITHM_ECIES = 4;
+    public static final int KM_ALGORITHM_EC = 3;
     public static final int KM_ALGORITHM_AES = 32;
-    public static final int KM_ALGORITHM_3DES = 33;
-    public static final int KM_ALGORITHM_SKIPJACK = 34;
-    public static final int KM_ALGORITHM_MARS = 48;
-    public static final int KM_ALGORITHM_RC6 = 49;
-    public static final int KM_ALGORITHM_SERPENT = 50;
-    public static final int KM_ALGORITHM_TWOFISH = 51;
-    public static final int KM_ALGORITHM_IDEA = 52;
-    public static final int KM_ALGORITHM_RC5 = 53;
-    public static final int KM_ALGORITHM_CAST5 = 54;
-    public static final int KM_ALGORITHM_BLOWFISH = 55;
-    public static final int KM_ALGORITHM_RC4 = 64;
-    public static final int KM_ALGORITHM_CHACHA20 = 65;
     public static final int KM_ALGORITHM_HMAC = 128;
 
     // Block modes.
     public static final int KM_MODE_FIRST_UNAUTHENTICATED = 1;
     public static final int KM_MODE_ECB = KM_MODE_FIRST_UNAUTHENTICATED;
     public static final int KM_MODE_CBC = 2;
-    public static final int KM_MODE_CBC_CTS = 3;
     public static final int KM_MODE_CTR = 4;
-    public static final int KM_MODE_OFB = 5;
-    public static final int KM_MODE_CFB = 6;
-    public static final int KM_MODE_XTS = 7;
     public static final int KM_MODE_FIRST_AUTHENTICATED = 32;
     public static final int KM_MODE_GCM = KM_MODE_FIRST_AUTHENTICATED;
-    public static final int KM_MODE_OCB = 33;
-    public static final int KM_MODE_CCM = 34;
-    public static final int KM_MODE_FIRST_MAC = 128;
-    public static final int KM_MODE_CMAC = KM_MODE_FIRST_MAC;
-    public static final int KM_MODE_POLY1305 = 129;
 
     // Padding modes.
     public static final int KM_PAD_NONE = 1;
@@ -132,11 +106,7 @@
     public static final int KM_PAD_RSA_PSS = 3;
     public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
     public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
-    public static final int KM_PAD_ANSI_X923 = 32;
-    public static final int KM_PAD_ISO_10126 = 33;
-    public static final int KM_PAD_ZERO = 64;
-    public static final int KM_PAD_PKCS7 = 65;
-    public static final int KM_PAD_ISO_7816_4 = 66;
+    public static final int KM_PAD_PKCS7 = 64;
 
     // Digest modes.
     public static final int KM_DIGEST_NONE = 0;
@@ -146,9 +116,6 @@
     public static final int KM_DIGEST_SHA_2_256 = 4;
     public static final int KM_DIGEST_SHA_2_384 = 5;
     public static final int KM_DIGEST_SHA_2_512 = 6;
-    public static final int KM_DIGEST_SHA_3_256 = 7;
-    public static final int KM_DIGEST_SHA_3_384 = 8;
-    public static final int KM_DIGEST_SHA_3_512 = 9;
 
     // Key origins.
     public static final int KM_ORIGIN_HARDWARE = 0;
@@ -168,9 +135,12 @@
     // Key formats.
     public static final int KM_KEY_FORMAT_X509 = 0;
     public static final int KM_KEY_FORMAT_PKCS8 = 1;
-    public static final int KM_KEY_FORMAT_PKCS12 = 2;
     public static final int KM_KEY_FORMAT_RAW = 3;
 
+    // User authenticators.
+    public static final int HW_AUTH_PASSWORD = 1 << 0;
+    public static final int HW_AUTH_FINGERPRINT = 1 << 1;
+
     // Error codes.
     public static final int KM_ERROR_OK = 0;
     public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
@@ -181,7 +151,7 @@
     public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6;
     public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7;
     public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8;
-    public static final int KM_ERROR_UNSUPPORTED_TAG_LENGTH = -9;
+    public static final int KM_ERROR_UNSUPPORTED_MAC_LENGTH = -9;
     public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10;
     public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11;
     public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12;
@@ -215,7 +185,6 @@
     public static final int KM_ERROR_INVALID_TAG = -40;
     public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED = -41;
     public static final int KM_ERROR_INVALID_RESCOPING = -42;
-    public static final int KM_ERROR_INVALID_DSA_PARAMS = -43;
     public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44;
     public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED = -45;
     public static final int KM_ERROR_OPERATION_CANCELLED = -46;
@@ -237,8 +206,8 @@
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_SIZE, "Unsupported key size");
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_BLOCK_MODE, "Unsupported block mode");
         sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, "Incompatible block mode");
-        sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG_LENGTH,
-                "Unsupported authentication tag length");
+        sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_MAC_LENGTH,
+                "Unsupported MAC or authentication tag length");
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PADDING_MODE, "Unsupported padding mode");
         sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PADDING_MODE, "Incompatible padding mode");
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_DIGEST, "Unsupported digest");
@@ -261,6 +230,7 @@
         sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG, "Unsupported tag");
         sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag");
         sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed");
+        sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 0860153..fa782e4 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -77,6 +77,12 @@
      */
     public static final int INTERRUPTION_FILTER_NONE = 3;
 
+    /**
+     * {@link #getCurrentInterruptionFilter() Interruption filter} constant -
+     *     Alarms only interruption filter.
+     */
+    public static final int INTERRUPTION_FILTER_ALARMS = 4;
+
     /** {@link #getCurrentInterruptionFilter() Interruption filter} constant - returned when
      * the value is unavailable for any reason.  For example, before the notification listener
      * is connected.
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 979a01b..56eb510 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -22,22 +22,25 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.provider.Settings.Global;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Locale;
 import java.util.Objects;
-
-import com.android.internal.R;
+import java.util.UUID;
 
 /**
  * Persisted configuration for zen mode.
@@ -47,10 +50,6 @@
 public class ZenModeConfig implements Parcelable {
     private static String TAG = "ZenModeConfig";
 
-    public static final String SLEEP_MODE_NIGHTS = "nights";
-    public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
-    public static final String SLEEP_MODE_DAYS_PREFIX = "days:";
-
     public static final int SOURCE_ANYONE = 0;
     public static final int SOURCE_CONTACT = 1;
     public static final int SOURCE_STAR = 2;
@@ -60,30 +59,27 @@
             Calendar.WEDNESDAY, Calendar.THURSDAY, Calendar.FRIDAY, Calendar.SATURDAY };
     public static final int[] WEEKNIGHT_DAYS = { Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY,
             Calendar.WEDNESDAY, Calendar.THURSDAY };
+    public static final int[] WEEKEND_DAYS = { Calendar.FRIDAY, Calendar.SATURDAY };
 
     public static final int[] MINUTE_BUCKETS = new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
     private static final int SECONDS_MS = 1000;
     private static final int MINUTES_MS = 60 * SECONDS_MS;
     private static final int ZERO_VALUE_MS = 10 * SECONDS_MS;
 
+    private static final boolean DEFAULT_ALLOW_REMINDERS = true;
     private static final boolean DEFAULT_ALLOW_EVENTS = true;
+    private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
 
-    private static final int XML_VERSION = 1;
+    private static final int XML_VERSION = 2;
     private static final String ZEN_TAG = "zen";
     private static final String ZEN_ATT_VERSION = "version";
     private static final String ALLOW_TAG = "allow";
     private static final String ALLOW_ATT_CALLS = "calls";
+    private static final String ALLOW_ATT_REPEAT_CALLERS = "repeatCallers";
     private static final String ALLOW_ATT_MESSAGES = "messages";
     private static final String ALLOW_ATT_FROM = "from";
+    private static final String ALLOW_ATT_REMINDERS = "reminders";
     private static final String ALLOW_ATT_EVENTS = "events";
-    private static final String SLEEP_TAG = "sleep";
-    private static final String SLEEP_ATT_MODE = "mode";
-    private static final String SLEEP_ATT_NONE = "none";
-
-    private static final String SLEEP_ATT_START_HR = "startHour";
-    private static final String SLEEP_ATT_START_MIN = "startMin";
-    private static final String SLEEP_ATT_END_HR = "endHour";
-    private static final String SLEEP_ATT_END_MIN = "endMin";
 
     private static final String CONDITION_TAG = "condition";
     private static final String CONDITION_ATT_COMPONENT = "component";
@@ -95,107 +91,115 @@
     private static final String CONDITION_ATT_STATE = "state";
     private static final String CONDITION_ATT_FLAGS = "flags";
 
-    private static final String EXIT_CONDITION_TAG = "exitCondition";
-    private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
+    private static final String MANUAL_TAG = "manual";
+    private static final String AUTOMATIC_TAG = "automatic";
+
+    private static final String RULE_ATT_ID = "id";
+    private static final String RULE_ATT_ENABLED = "enabled";
+    private static final String RULE_ATT_SNOOZING = "snoozing";
+    private static final String RULE_ATT_NAME = "name";
+    private static final String RULE_ATT_COMPONENT = "component";
+    private static final String RULE_ATT_ZEN = "zen";
+    private static final String RULE_ATT_CONDITION_ID = "conditionId";
 
     public boolean allowCalls;
+    public boolean allowRepeatCallers = DEFAULT_ALLOW_REPEAT_CALLERS;
     public boolean allowMessages;
+    public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
     public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
     public int allowFrom = SOURCE_ANYONE;
 
-    public String sleepMode;
-    public int sleepStartHour;   // 0-23
-    public int sleepStartMinute; // 0-59
-    public int sleepEndHour;
-    public int sleepEndMinute;
-    public boolean sleepNone;    // false = priority, true = none
-    public ComponentName[] conditionComponents;
-    public Uri[] conditionIds;
-    public Condition exitCondition;
-    public ComponentName exitConditionComponent;
+    public ZenRule manualRule;
+    public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
 
     public ZenModeConfig() { }
 
     public ZenModeConfig(Parcel source) {
         allowCalls = source.readInt() == 1;
+        allowRepeatCallers = source.readInt() == 1;
         allowMessages = source.readInt() == 1;
+        allowReminders = source.readInt() == 1;
         allowEvents = source.readInt() == 1;
-        if (source.readInt() == 1) {
-            sleepMode = source.readString();
-        }
-        sleepStartHour = source.readInt();
-        sleepStartMinute = source.readInt();
-        sleepEndHour = source.readInt();
-        sleepEndMinute = source.readInt();
-        sleepNone = source.readInt() == 1;
-        int len = source.readInt();
-        if (len > 0) {
-            conditionComponents = new ComponentName[len];
-            source.readTypedArray(conditionComponents, ComponentName.CREATOR);
-        }
-        len = source.readInt();
-        if (len > 0) {
-            conditionIds = new Uri[len];
-            source.readTypedArray(conditionIds, Uri.CREATOR);
-        }
         allowFrom = source.readInt();
-        exitCondition = source.readParcelable(null);
-        exitConditionComponent = source.readParcelable(null);
+        manualRule = source.readParcelable(null);
+        final int len = source.readInt();
+        if (len > 0) {
+            final String[] ids = new String[len];
+            final ZenRule[] rules = new ZenRule[len];
+            source.readStringArray(ids);
+            source.readTypedArray(rules, ZenRule.CREATOR);
+            for (int i = 0; i < len; i++) {
+                automaticRules.put(ids[i], rules[i]);
+            }
+        }
     }
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(allowCalls ? 1 : 0);
+        dest.writeInt(allowRepeatCallers ? 1 : 0);
         dest.writeInt(allowMessages ? 1 : 0);
+        dest.writeInt(allowReminders ? 1 : 0);
         dest.writeInt(allowEvents ? 1 : 0);
-        if (sleepMode != null) {
-            dest.writeInt(1);
-            dest.writeString(sleepMode);
-        } else {
-            dest.writeInt(0);
-        }
-        dest.writeInt(sleepStartHour);
-        dest.writeInt(sleepStartMinute);
-        dest.writeInt(sleepEndHour);
-        dest.writeInt(sleepEndMinute);
-        dest.writeInt(sleepNone ? 1 : 0);
-        if (conditionComponents != null && conditionComponents.length > 0) {
-            dest.writeInt(conditionComponents.length);
-            dest.writeTypedArray(conditionComponents, 0);
-        } else {
-            dest.writeInt(0);
-        }
-        if (conditionIds != null && conditionIds.length > 0) {
-            dest.writeInt(conditionIds.length);
-            dest.writeTypedArray(conditionIds, 0);
-        } else {
-            dest.writeInt(0);
-        }
         dest.writeInt(allowFrom);
-        dest.writeParcelable(exitCondition, 0);
-        dest.writeParcelable(exitConditionComponent, 0);
+        dest.writeParcelable(manualRule, 0);
+        if (!automaticRules.isEmpty()) {
+            final int len = automaticRules.size();
+            final String[] ids = new String[len];
+            final ZenRule[] rules = new ZenRule[len];
+            for (int i = 0; i < len; i++) {
+                ids[i] = automaticRules.keyAt(i);
+                rules[i] = automaticRules.valueAt(i);
+            }
+            dest.writeInt(len);
+            dest.writeStringArray(ids);
+            dest.writeTypedArray(rules, 0);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     @Override
     public String toString() {
         return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
             .append("allowCalls=").append(allowCalls)
+            .append(",allowRepeatCallers=").append(allowRepeatCallers)
             .append(",allowMessages=").append(allowMessages)
             .append(",allowFrom=").append(sourceToString(allowFrom))
+            .append(",allowReminders=").append(allowReminders)
             .append(",allowEvents=").append(allowEvents)
-            .append(",sleepMode=").append(sleepMode)
-            .append(",sleepStart=").append(sleepStartHour).append('.').append(sleepStartMinute)
-            .append(",sleepEnd=").append(sleepEndHour).append('.').append(sleepEndMinute)
-            .append(",sleepNone=").append(sleepNone)
-            .append(",conditionComponents=")
-            .append(conditionComponents == null ? null : TextUtils.join(",", conditionComponents))
-            .append(",conditionIds=")
-            .append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
-            .append(",exitCondition=").append(exitCondition)
-            .append(",exitConditionComponent=").append(exitConditionComponent)
+            .append(",automaticRules=").append(automaticRules)
+            .append(",manualRule=").append(manualRule)
             .append(']').toString();
     }
 
+    public boolean isValid() {
+        if (!isValidManualRule(manualRule)) return false;
+        final int N = automaticRules.size();
+        for (int i = 0; i < N; i++) {
+            if (!isValidAutomaticRule(automaticRules.valueAt(i))) return false;
+        }
+        return true;
+    }
+
+    private static boolean isValidManualRule(ZenRule rule) {
+        return rule == null || Global.isValidZenMode(rule.zenMode) && sameCondition(rule);
+    }
+
+    private static boolean isValidAutomaticRule(ZenRule rule) {
+        return rule != null && !TextUtils.isEmpty(rule.name) && Global.isValidZenMode(rule.zenMode)
+                && rule.conditionId != null && sameCondition(rule);
+    }
+
+    private static boolean sameCondition(ZenRule rule) {
+        if (rule == null) return false;
+        if (rule.conditionId == null) {
+            return rule.condition == null;
+        } else {
+            return rule.condition == null || rule.conditionId.equals(rule.condition.id);
+        }
+    }
+
     public static String sourceToString(int source) {
         switch (source) {
             case SOURCE_ANYONE:
@@ -215,48 +219,34 @@
         if (o == this) return true;
         final ZenModeConfig other = (ZenModeConfig) o;
         return other.allowCalls == allowCalls
+                && other.allowRepeatCallers == allowRepeatCallers
                 && other.allowMessages == allowMessages
                 && other.allowFrom == allowFrom
+                && other.allowReminders == allowReminders
                 && other.allowEvents == allowEvents
-                && Objects.equals(other.sleepMode, sleepMode)
-                && other.sleepNone == sleepNone
-                && other.sleepStartHour == sleepStartHour
-                && other.sleepStartMinute == sleepStartMinute
-                && other.sleepEndHour == sleepEndHour
-                && other.sleepEndMinute == sleepEndMinute
-                && Objects.deepEquals(other.conditionComponents, conditionComponents)
-                && Objects.deepEquals(other.conditionIds, conditionIds)
-                && Objects.equals(other.exitCondition, exitCondition)
-                && Objects.equals(other.exitConditionComponent, exitConditionComponent);
+                && Objects.equals(other.automaticRules, automaticRules)
+                && Objects.equals(other.manualRule, manualRule);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(allowCalls, allowMessages, allowFrom, allowEvents, sleepMode, sleepNone,
-                sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
-                Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
-                exitCondition, exitConditionComponent);
+        return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowFrom,
+                allowReminders, allowEvents, automaticRules, manualRule);
     }
 
-    public boolean isValid() {
-        return isValidHour(sleepStartHour) && isValidMinute(sleepStartMinute)
-                && isValidHour(sleepEndHour) && isValidMinute(sleepEndMinute)
-                && isValidSleepMode(sleepMode);
+    private static String toDayList(int[] days) {
+        if (days == null || days.length == 0) return "";
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < days.length; i++) {
+            if (i > 0) sb.append('.');
+            sb.append(days[i]);
+        }
+        return sb.toString();
     }
 
-    public static boolean isValidSleepMode(String sleepMode) {
-        return sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS)
-                || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS) || tryParseDays(sleepMode) != null;
-    }
-
-    public static int[] tryParseDays(String sleepMode) {
-        if (sleepMode == null) return null;
-        sleepMode = sleepMode.trim();
-        if (SLEEP_MODE_NIGHTS.equals(sleepMode)) return ALL_DAYS;
-        if (SLEEP_MODE_WEEKNIGHTS.equals(sleepMode)) return WEEKNIGHT_DAYS;
-        if (!sleepMode.startsWith(SLEEP_MODE_DAYS_PREFIX)) return null;
-        if (sleepMode.equals(SLEEP_MODE_DAYS_PREFIX)) return null;
-        final String[] tokens = sleepMode.substring(SLEEP_MODE_DAYS_PREFIX.length()).split(",");
+    private static int[] tryParseDayList(String dayList, String sep) {
+        if (dayList == null) return null;
+        final String[] tokens = dayList.split(sep);
         if (tokens.length == 0) return null;
         final int[] rt = new int[tokens.length];
         for (int i = 0; i < tokens.length; i++) {
@@ -276,7 +266,7 @@
         }
     }
 
-    public static ZenModeConfig readXml(XmlPullParser parser)
+    public static ZenModeConfig readXml(XmlPullParser parser, Migration migration)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
         if (type != XmlPullParser.START_TAG) return null;
@@ -284,52 +274,35 @@
         if (!ZEN_TAG.equals(tag)) return null;
         final ZenModeConfig rt = new ZenModeConfig();
         final int version = safeInt(parser, ZEN_ATT_VERSION, XML_VERSION);
-        final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
-        final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
+        if (version == 1) {
+            final XmlV1 v1 = XmlV1.readXml(parser);
+            return migration.migrate(v1);
+        }
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
             tag = parser.getName();
             if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
-                if (!conditionComponents.isEmpty()) {
-                    rt.conditionComponents = conditionComponents
-                            .toArray(new ComponentName[conditionComponents.size()]);
-                    rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
-                }
                 return rt;
             }
             if (type == XmlPullParser.START_TAG) {
                 if (ALLOW_TAG.equals(tag)) {
                     rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
+                    rt.allowRepeatCallers = safeBoolean(parser, ALLOW_ATT_REPEAT_CALLERS,
+                            DEFAULT_ALLOW_REPEAT_CALLERS);
                     rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
+                    rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
+                            DEFAULT_ALLOW_REMINDERS);
                     rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS, DEFAULT_ALLOW_EVENTS);
                     rt.allowFrom = safeInt(parser, ALLOW_ATT_FROM, SOURCE_ANYONE);
                     if (rt.allowFrom < SOURCE_ANYONE || rt.allowFrom > MAX_SOURCE) {
                         throw new IndexOutOfBoundsException("bad source in config:" + rt.allowFrom);
                     }
-                } else if (SLEEP_TAG.equals(tag)) {
-                    final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
-                    rt.sleepMode = isValidSleepMode(mode)? mode : null;
-                    rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
-                    final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
-                    final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
-                    final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
-                    final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0);
-                    rt.sleepStartHour = isValidHour(startHour) ? startHour : 0;
-                    rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
-                    rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
-                    rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
-                } else if (CONDITION_TAG.equals(tag)) {
-                    final ComponentName component =
-                            safeComponentName(parser, CONDITION_ATT_COMPONENT);
-                    final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
-                    if (component != null && conditionId != null) {
-                        conditionComponents.add(component);
-                        conditionIds.add(conditionId);
-                    }
-                } else if (EXIT_CONDITION_TAG.equals(tag)) {
-                    rt.exitCondition = readConditionXml(parser);
-                    if (rt.exitCondition != null) {
-                        rt.exitConditionComponent =
-                                safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+                } else if (MANUAL_TAG.equals(tag)) {
+                    rt.manualRule = readRuleXml(parser);
+                } else if (AUTOMATIC_TAG.equals(tag)) {
+                    final String id = parser.getAttributeValue(null, RULE_ATT_ID);
+                    final ZenRule automaticRule = readRuleXml(parser);
+                    if (id != null && automaticRule != null) {
+                        rt.automaticRules.put(id, automaticRule);
                     }
                 }
             }
@@ -343,44 +316,68 @@
 
         out.startTag(null, ALLOW_TAG);
         out.attribute(null, ALLOW_ATT_CALLS, Boolean.toString(allowCalls));
+        out.attribute(null, ALLOW_ATT_REPEAT_CALLERS, Boolean.toString(allowRepeatCallers));
         out.attribute(null, ALLOW_ATT_MESSAGES, Boolean.toString(allowMessages));
+        out.attribute(null, ALLOW_ATT_REMINDERS, Boolean.toString(allowReminders));
         out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
         out.attribute(null, ALLOW_ATT_FROM, Integer.toString(allowFrom));
         out.endTag(null, ALLOW_TAG);
 
-        out.startTag(null, SLEEP_TAG);
-        if (sleepMode != null) {
-            out.attribute(null, SLEEP_ATT_MODE, sleepMode);
+        if (manualRule != null) {
+            out.startTag(null, MANUAL_TAG);
+            writeRuleXml(manualRule, out);
+            out.endTag(null, MANUAL_TAG);
         }
-        out.attribute(null, SLEEP_ATT_NONE, Boolean.toString(sleepNone));
-        out.attribute(null, SLEEP_ATT_START_HR, Integer.toString(sleepStartHour));
-        out.attribute(null, SLEEP_ATT_START_MIN, Integer.toString(sleepStartMinute));
-        out.attribute(null, SLEEP_ATT_END_HR, Integer.toString(sleepEndHour));
-        out.attribute(null, SLEEP_ATT_END_MIN, Integer.toString(sleepEndMinute));
-        out.endTag(null, SLEEP_TAG);
-
-        if (conditionComponents != null && conditionIds != null
-                && conditionComponents.length == conditionIds.length) {
-            for (int i = 0; i < conditionComponents.length; i++) {
-                out.startTag(null, CONDITION_TAG);
-                out.attribute(null, CONDITION_ATT_COMPONENT,
-                        conditionComponents[i].flattenToString());
-                out.attribute(null, CONDITION_ATT_ID, conditionIds[i].toString());
-                out.endTag(null, CONDITION_TAG);
-            }
-        }
-        if (exitCondition != null && exitConditionComponent != null) {
-            out.startTag(null, EXIT_CONDITION_TAG);
-            out.attribute(null, EXIT_CONDITION_ATT_COMPONENT,
-                    exitConditionComponent.flattenToString());
-            writeConditionXml(exitCondition, out);
-            out.endTag(null, EXIT_CONDITION_TAG);
+        final int N = automaticRules.size();
+        for (int i = 0; i < N; i++) {
+            final String id = automaticRules.keyAt(i);
+            final ZenRule automaticRule = automaticRules.valueAt(i);
+            out.startTag(null, AUTOMATIC_TAG);
+            out.attribute(null, RULE_ATT_ID, id);
+            writeRuleXml(automaticRule, out);
+            out.endTag(null, AUTOMATIC_TAG);
         }
         out.endTag(null, ZEN_TAG);
     }
 
+    public static ZenRule readRuleXml(XmlPullParser parser) {
+        final ZenRule rt = new ZenRule();
+        rt.enabled = safeBoolean(parser, RULE_ATT_ENABLED, true);
+        rt.snoozing = safeBoolean(parser, RULE_ATT_SNOOZING, false);
+        rt.name = parser.getAttributeValue(null, RULE_ATT_NAME);
+        final String zen = parser.getAttributeValue(null, RULE_ATT_ZEN);
+        rt.zenMode = tryParseZenMode(zen, -1);
+        if (rt.zenMode == -1) {
+            Slog.w(TAG, "Bad zen mode in rule xml:" + zen);
+            return null;
+        }
+        rt.conditionId = safeUri(parser, RULE_ATT_CONDITION_ID);
+        rt.component = safeComponentName(parser, RULE_ATT_COMPONENT);
+        rt.condition = readConditionXml(parser);
+        return rt.condition != null ? rt : null;
+    }
+
+    public static void writeRuleXml(ZenRule rule, XmlSerializer out) throws IOException {
+        out.attribute(null, RULE_ATT_ENABLED, Boolean.toString(rule.enabled));
+        out.attribute(null, RULE_ATT_SNOOZING, Boolean.toString(rule.snoozing));
+        if (rule.name != null) {
+            out.attribute(null, RULE_ATT_NAME, rule.name);
+        }
+        out.attribute(null, RULE_ATT_ZEN, Integer.toString(rule.zenMode));
+        if (rule.component != null) {
+            out.attribute(null, RULE_ATT_COMPONENT, rule.component.flattenToString());
+        }
+        if (rule.conditionId != null) {
+            out.attribute(null, RULE_ATT_CONDITION_ID, rule.conditionId.toString());
+        }
+        if (rule.condition != null) {
+            writeConditionXml(rule.condition, out);
+        }
+    }
+
     public static Condition readConditionXml(XmlPullParser parser) {
         final Uri id = safeUri(parser, CONDITION_ATT_ID);
+        if (id == null) return null;
         final String summary = parser.getAttributeValue(null, CONDITION_ATT_SUMMARY);
         final String line1 = parser.getAttributeValue(null, CONDITION_ATT_LINE1);
         final String line2 = parser.getAttributeValue(null, CONDITION_ATT_LINE2);
@@ -436,6 +433,14 @@
         return Uri.parse(val);
     }
 
+    public ArraySet<String> getAutomaticRuleNames() {
+        final ArraySet<String> rt = new ArraySet<String>();
+        for (int i = 0; i < automaticRules.size(); i++) {
+            rt.add(automaticRules.valueAt(i).name);
+        }
+        return rt;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -465,17 +470,6 @@
         }
     };
 
-    public DowntimeInfo toDowntimeInfo() {
-        final DowntimeInfo downtime = new DowntimeInfo();
-        downtime.startHour = sleepStartHour;
-        downtime.startMinute = sleepStartMinute;
-        downtime.endHour = sleepEndHour;
-        downtime.endMinute = sleepEndMinute;
-        downtime.mode = sleepMode;
-        downtime.none = sleepNone;
-        return downtime;
-    }
-
     public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) {
         final long now = System.currentTimeMillis();
         final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
@@ -538,38 +532,77 @@
         return tryParseCountdownConditionId(conditionId) != 0;
     }
 
-    // Built-in downtime conditions
-    // e.g. condition://android/downtime?start=10.00&end=7.00&mode=days%3A5%2C6&none=false
-    public static final String DOWNTIME_PATH = "downtime";
+    // built-in schedule conditions
+    public static final String SCHEDULE_PATH = "schedule";
 
-    public static Uri toDowntimeConditionId(DowntimeInfo downtime) {
+    public static class ScheduleInfo {
+        public int[] days;
+        public int startHour;
+        public int startMinute;
+        public int endHour;
+        public int endMinute;
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (!(o instanceof ScheduleInfo)) return false;
+            final ScheduleInfo other = (ScheduleInfo) o;
+            return toDayList(days).equals(toDayList(other.days))
+                    && startHour == other.startHour
+                    && startMinute == other.startMinute
+                    && endHour == other.endHour
+                    && endMinute == other.endMinute;
+        }
+
+        public ScheduleInfo copy() {
+            final ScheduleInfo rt = new ScheduleInfo();
+            if (days != null) {
+                rt.days = new int[days.length];
+                System.arraycopy(days, 0, rt.days, 0, days.length);
+            }
+            rt.startHour = startHour;
+            rt.startMinute = startMinute;
+            rt.endHour = endHour;
+            rt.endMinute = endMinute;
+            return rt;
+        }
+    }
+
+    public static Uri toScheduleConditionId(ScheduleInfo schedule) {
         return new Uri.Builder().scheme(Condition.SCHEME)
                 .authority(SYSTEM_AUTHORITY)
-                .appendPath(DOWNTIME_PATH)
-                .appendQueryParameter("start", downtime.startHour + "." + downtime.startMinute)
-                .appendQueryParameter("end", downtime.endHour + "." + downtime.endMinute)
-                .appendQueryParameter("mode", downtime.mode)
-                .appendQueryParameter("none", Boolean.toString(downtime.none))
+                .appendPath(SCHEDULE_PATH)
+                .appendQueryParameter("days", toDayList(schedule.days))
+                .appendQueryParameter("start", schedule.startHour + "." + schedule.startMinute)
+                .appendQueryParameter("end", schedule.endHour + "." + schedule.endMinute)
                 .build();
     }
 
-    public static DowntimeInfo tryParseDowntimeConditionId(Uri conditionId) {
-        if (!Condition.isValidId(conditionId, SYSTEM_AUTHORITY)
-                || conditionId.getPathSegments().size() != 1
-                || !DOWNTIME_PATH.equals(conditionId.getPathSegments().get(0))) {
-            return null;
-        }
+    public static boolean isValidScheduleConditionId(Uri conditionId) {
+        return tryParseScheduleConditionId(conditionId) != null;
+    }
+
+    public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
+        final boolean isSchedule =  conditionId != null
+                && conditionId.getScheme().equals(Condition.SCHEME)
+                && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
+                && conditionId.getPathSegments().size() == 1
+                && conditionId.getPathSegments().get(0).equals(ZenModeConfig.SCHEDULE_PATH);
+        if (!isSchedule) return null;
         final int[] start = tryParseHourAndMinute(conditionId.getQueryParameter("start"));
         final int[] end = tryParseHourAndMinute(conditionId.getQueryParameter("end"));
         if (start == null || end == null) return null;
-        final DowntimeInfo downtime = new DowntimeInfo();
-        downtime.startHour = start[0];
-        downtime.startMinute = start[1];
-        downtime.endHour = end[0];
-        downtime.endMinute = end[1];
-        downtime.mode = conditionId.getQueryParameter("mode");
-        downtime.none = Boolean.toString(true).equals(conditionId.getQueryParameter("none"));
-        return downtime;
+        final ScheduleInfo rt = new ScheduleInfo();
+        rt.days = tryParseDayList(conditionId.getQueryParameter("days"), "\\.");
+        rt.startHour = start[0];
+        rt.startMinute = start[1];
+        rt.endHour = end[0];
+        rt.endMinute = end[1];
+        return rt;
     }
 
     private static int[] tryParseHourAndMinute(String value) {
@@ -581,36 +614,268 @@
         return isValidHour(hour) && isValidMinute(minute) ? new int[] { hour, minute } : null;
     }
 
-    public static boolean isValidDowntimeConditionId(Uri conditionId) {
-        return tryParseDowntimeConditionId(conditionId) != null;
+    private static int tryParseZenMode(String value, int defValue) {
+        final int rt = tryParseInt(value, defValue);
+        return Global.isValidZenMode(rt) ? rt : defValue;
     }
 
-    public static class DowntimeInfo {
-        public int startHour;   // 0-23
-        public int startMinute; // 0-59
-        public int endHour;
-        public int endMinute;
-        public String mode;
-        public boolean none;
+    public String newRuleId() {
+        return UUID.randomUUID().toString().replace("-", "");
+    }
+
+    public static String getConditionLine1(Context context, ZenModeConfig config,
+            int userHandle) {
+        return getConditionLine(context, config, userHandle, true /*useLine1*/);
+    }
+
+    public static String getConditionSummary(Context context, ZenModeConfig config,
+            int userHandle) {
+        return getConditionLine(context, config, userHandle, false /*useLine1*/);
+    }
+
+    private static String getConditionLine(Context context, ZenModeConfig config,
+            int userHandle, boolean useLine1) {
+        if (config == null) return "";
+        if (config.manualRule != null) {
+            final Uri id = config.manualRule.conditionId;
+            if (id == null) {
+                return context.getString(com.android.internal.R.string.zen_mode_forever);
+            }
+            final long time = tryParseCountdownConditionId(id);
+            Condition c = config.manualRule.condition;
+            if (time > 0) {
+                final long now = System.currentTimeMillis();
+                final long span = time - now;
+                c = toTimeCondition(context,
+                        time, Math.round(span / (float) MINUTES_MS), now, userHandle);
+            }
+            final String rt = c == null ? "" : useLine1 ? c.line1 : c.summary;
+            return TextUtils.isEmpty(rt) ? "" : rt;
+        }
+        String summary = "";
+        for (ZenRule automaticRule : config.automaticRules.values()) {
+            if (automaticRule.enabled && !automaticRule.snoozing
+                    && automaticRule.isTrueOrUnknown()) {
+                if (summary.isEmpty()) {
+                    summary = automaticRule.name;
+                } else {
+                    summary = context.getResources()
+                            .getString(R.string.zen_mode_rule_name_combination, summary,
+                                    automaticRule.name);
+                }
+            }
+        }
+        return summary;
+    }
+
+    public static class ZenRule implements Parcelable {
+        public boolean enabled;
+        public boolean snoozing;         // user manually disabled this instance
+        public String name;              // required for automatic (unique)
+        public int zenMode;
+        public Uri conditionId;          // required for automatic
+        public Condition condition;      // optional
+        public ComponentName component;  // optional
+
+        public ZenRule() { }
+
+        public ZenRule(Parcel source) {
+            enabled = source.readInt() == 1;
+            snoozing = source.readInt() == 1;
+            if (source.readInt() == 1) {
+                name = source.readString();
+            }
+            zenMode = source.readInt();
+            conditionId = source.readParcelable(null);
+            condition = source.readParcelable(null);
+            component = source.readParcelable(null);
+        }
 
         @Override
-        public int hashCode() {
+        public int describeContents() {
             return 0;
         }
 
         @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(enabled ? 1 : 0);
+            dest.writeInt(snoozing ? 1 : 0);
+            if (name != null) {
+                dest.writeInt(1);
+                dest.writeString(name);
+            } else {
+                dest.writeInt(0);
+            }
+            dest.writeInt(zenMode);
+            dest.writeParcelable(conditionId, 0);
+            dest.writeParcelable(condition, 0);
+            dest.writeParcelable(component, 0);
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder(ZenRule.class.getSimpleName()).append('[')
+                    .append("enabled=").append(enabled)
+                    .append(",snoozing=").append(snoozing)
+                    .append(",name=").append(name)
+                    .append(",zenMode=").append(Global.zenModeToString(zenMode))
+                    .append(",conditionId=").append(conditionId)
+                    .append(",condition=").append(condition)
+                    .append(",component=").append(component)
+                    .append(']').toString();
+        }
+
+        @Override
         public boolean equals(Object o) {
-            if (!(o instanceof DowntimeInfo)) return false;
-            final DowntimeInfo other = (DowntimeInfo) o;
-            return startHour == other.startHour
-                    && startMinute == other.startMinute
-                    && endHour == other.endHour
-                    && endMinute == other.endMinute
-                    && Objects.equals(mode, other.mode)
-                    && none == other.none;
+            if (!(o instanceof ZenRule)) return false;
+            if (o == this) return true;
+            final ZenRule other = (ZenRule) o;
+            return other.enabled == enabled
+                    && other.snoozing == snoozing
+                    && Objects.equals(other.name, name)
+                    && other.zenMode == zenMode
+                    && Objects.equals(other.conditionId, conditionId)
+                    && Objects.equals(other.condition, condition)
+                    && Objects.equals(other.component, component);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
+                    component);
+        }
+
+        public boolean isTrueOrUnknown() {
+            return condition == null || condition.state == Condition.STATE_TRUE
+                    || condition.state == Condition.STATE_UNKNOWN;
+        }
+
+        public static final Parcelable.Creator<ZenRule> CREATOR
+                = new Parcelable.Creator<ZenRule>() {
+            @Override
+            public ZenRule createFromParcel(Parcel source) {
+                return new ZenRule(source);
+            }
+            @Override
+            public ZenRule[] newArray(int size) {
+                return new ZenRule[size];
+            }
+        };
+    }
+
+    // Legacy config
+    public static final class XmlV1 {
+        public static final String SLEEP_MODE_NIGHTS = "nights";
+        public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
+        public static final String SLEEP_MODE_DAYS_PREFIX = "days:";
+
+        private static final String EXIT_CONDITION_TAG = "exitCondition";
+        private static final String EXIT_CONDITION_ATT_COMPONENT = "component";
+        private static final String SLEEP_TAG = "sleep";
+        private static final String SLEEP_ATT_MODE = "mode";
+        private static final String SLEEP_ATT_NONE = "none";
+
+        private static final String SLEEP_ATT_START_HR = "startHour";
+        private static final String SLEEP_ATT_START_MIN = "startMin";
+        private static final String SLEEP_ATT_END_HR = "endHour";
+        private static final String SLEEP_ATT_END_MIN = "endMin";
+
+        public boolean allowCalls;
+        public boolean allowMessages;
+        public boolean allowReminders = DEFAULT_ALLOW_REMINDERS;
+        public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
+        public int allowFrom = SOURCE_ANYONE;
+
+        public String sleepMode;     // nights, weeknights, days:1,2,3  Calendar.days
+        public int sleepStartHour;   // 0-23
+        public int sleepStartMinute; // 0-59
+        public int sleepEndHour;
+        public int sleepEndMinute;
+        public boolean sleepNone;    // false = priority, true = none
+        public ComponentName[] conditionComponents;
+        public Uri[] conditionIds;
+        public Condition exitCondition;  // manual exit condition
+        public ComponentName exitConditionComponent;  // manual exit condition component
+
+        private static boolean isValidSleepMode(String sleepMode) {
+            return sleepMode == null || sleepMode.equals(SLEEP_MODE_NIGHTS)
+                    || sleepMode.equals(SLEEP_MODE_WEEKNIGHTS) || tryParseDays(sleepMode) != null;
+        }
+
+        public static int[] tryParseDays(String sleepMode) {
+            if (sleepMode == null) return null;
+            sleepMode = sleepMode.trim();
+            if (SLEEP_MODE_NIGHTS.equals(sleepMode)) return ALL_DAYS;
+            if (SLEEP_MODE_WEEKNIGHTS.equals(sleepMode)) return WEEKNIGHT_DAYS;
+            if (!sleepMode.startsWith(SLEEP_MODE_DAYS_PREFIX)) return null;
+            if (sleepMode.equals(SLEEP_MODE_DAYS_PREFIX)) return null;
+            return tryParseDayList(sleepMode.substring(SLEEP_MODE_DAYS_PREFIX.length()), ",");
+        }
+
+        public static XmlV1 readXml(XmlPullParser parser)
+                throws XmlPullParserException, IOException {
+            int type;
+            String tag;
+            XmlV1 rt = new XmlV1();
+            final ArrayList<ComponentName> conditionComponents = new ArrayList<ComponentName>();
+            final ArrayList<Uri> conditionIds = new ArrayList<Uri>();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                tag = parser.getName();
+                if (type == XmlPullParser.END_TAG && ZEN_TAG.equals(tag)) {
+                    if (!conditionComponents.isEmpty()) {
+                        rt.conditionComponents = conditionComponents
+                                .toArray(new ComponentName[conditionComponents.size()]);
+                        rt.conditionIds = conditionIds.toArray(new Uri[conditionIds.size()]);
+                    }
+                    return rt;
+                }
+                if (type == XmlPullParser.START_TAG) {
+                    if (ALLOW_TAG.equals(tag)) {
+                        rt.allowCalls = safeBoolean(parser, ALLOW_ATT_CALLS, false);
+                        rt.allowMessages = safeBoolean(parser, ALLOW_ATT_MESSAGES, false);
+                        rt.allowReminders = safeBoolean(parser, ALLOW_ATT_REMINDERS,
+                                DEFAULT_ALLOW_REMINDERS);
+                        rt.allowEvents = safeBoolean(parser, ALLOW_ATT_EVENTS,
+                                DEFAULT_ALLOW_EVENTS);
+                        rt.allowFrom = safeInt(parser, ALLOW_ATT_FROM, SOURCE_ANYONE);
+                        if (rt.allowFrom < SOURCE_ANYONE || rt.allowFrom > MAX_SOURCE) {
+                            throw new IndexOutOfBoundsException("bad source in config:"
+                                    + rt.allowFrom);
+                        }
+                    } else if (SLEEP_TAG.equals(tag)) {
+                        final String mode = parser.getAttributeValue(null, SLEEP_ATT_MODE);
+                        rt.sleepMode = isValidSleepMode(mode)? mode : null;
+                        rt.sleepNone = safeBoolean(parser, SLEEP_ATT_NONE, false);
+                        final int startHour = safeInt(parser, SLEEP_ATT_START_HR, 0);
+                        final int startMinute = safeInt(parser, SLEEP_ATT_START_MIN, 0);
+                        final int endHour = safeInt(parser, SLEEP_ATT_END_HR, 0);
+                        final int endMinute = safeInt(parser, SLEEP_ATT_END_MIN, 0);
+                        rt.sleepStartHour = isValidHour(startHour) ? startHour : 0;
+                        rt.sleepStartMinute = isValidMinute(startMinute) ? startMinute : 0;
+                        rt.sleepEndHour = isValidHour(endHour) ? endHour : 0;
+                        rt.sleepEndMinute = isValidMinute(endMinute) ? endMinute : 0;
+                    } else if (CONDITION_TAG.equals(tag)) {
+                        final ComponentName component =
+                                safeComponentName(parser, CONDITION_ATT_COMPONENT);
+                        final Uri conditionId = safeUri(parser, CONDITION_ATT_ID);
+                        if (component != null && conditionId != null) {
+                            conditionComponents.add(component);
+                            conditionIds.add(conditionId);
+                        }
+                    } else if (EXIT_CONDITION_TAG.equals(tag)) {
+                        rt.exitCondition = readConditionXml(parser);
+                        if (rt.exitCondition != null) {
+                            rt.exitConditionComponent =
+                                    safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
+                        }
+                    }
+                }
+            }
+            throw new IllegalStateException("Failed to reach END_DOCUMENT");
         }
     }
 
-    // built-in next alarm conditions
-    public static final String NEXT_ALARM_PATH = "next_alarm";
+    public interface Migration {
+        ZenModeConfig migrate(XmlV1 v1);
+    }
 }
diff --git a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
index 52db223..0071a33 100644
--- a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
+++ b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl
@@ -16,6 +16,8 @@
 
 package android.service.persistentdata;
 
+import android.app.PendingIntent;
+import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -30,6 +32,7 @@
     int write(in byte[] data);
     byte[] read();
     void wipe();
+    void wipeIfAllowed(in Bundle bundle, in PendingIntent pi);
     int getDataBlockSize();
     long getMaximumDataBlockSize();
 
diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
index 0ffdf68..31570c6 100644
--- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java
+++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java
@@ -17,6 +17,8 @@
 package android.service.persistentdata;
 
 import android.annotation.SystemApi;
+import android.app.PendingIntent;
+import android.os.Bundle;
 import android.os.RemoteException;
 import android.util.Slog;
 
@@ -41,6 +43,56 @@
 @SystemApi
 public class PersistentDataBlockManager {
     private static final String TAG = PersistentDataBlockManager.class.getSimpleName();
+
+    /**
+     * Broadcast action that will be called when the {@link #wipeIfAllowed(Bundle,PendingIntent)}
+     * method is called.  A broadcast with this action will be sent to the package allowed to write
+     * to the persistent data block. Packages receiving this broadcasts should respond by using the
+     * {@link android.app.PendingIntent} sent in the {@link #EXTRA_WIPE_IF_ALLOWED_CALLBACK} extra.
+     */
+    public static final String ACTION_WIPE_IF_ALLOWED
+            = "android.service.persistentdata.action.WIPE_IF_ALLOWED";
+
+    /**
+     * A {@link android.os.Parcelable} extra of type {@link android.app.PendingIntent} used to
+     * response to {@link #wipeIfAllowed(Bundle,PendingIntent)}. This extra will set in broadcasts
+     * with an action of {@link #ACTION_WIPE_IF_ALLOWED}.
+     */
+    public static final String EXTRA_WIPE_IF_ALLOWED_CALLBACK
+            = "android.service.persistentdata.extra.WIPE_IF_ALLOWED_CALLBACK";
+
+    /**
+     * Result code indicating that the data block was wiped.
+     *
+     * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to
+     * {@link #wipeIfAllowed(Bundle,PendingIntent)}
+     */
+    public static final int STATUS_SUCCESS = 0;
+
+    /**
+     * Result code indicating that a remote exception was received while processing the request.
+     *
+     * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to
+     * {@link #wipeIfAllowed(Bundle,PendingIntent)}
+     */
+    public static final int STATUS_ERROR_REMOTE_EXCEPTION = 1;
+
+    /**
+     * Result code indicating that a network error occurred while processing the request.
+     *
+     * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to
+     * {@link #wipeIfAllowed(Bundle,PendingIntent)}
+     */
+    public static final int STATUS_ERROR_NETWORK_ERROR = 2;
+
+    /**
+     * Result code indicating that the data block could not be cleared with the provided data.
+     *
+     * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to
+     * {@link #wipeIfAllowed(Bundle,PendingIntent)}
+     */
+    public static final int STATUS_ERROR_NOT_COMPLIANT = 3;
+
     private IPersistentDataBlockService sService;
 
     public PersistentDataBlockManager(IPersistentDataBlockService service) {
@@ -118,6 +170,28 @@
     }
 
     /**
+     * Attempt to wipe the data block by sending a broadcast to the package allowed to modify the
+     * datablock. The allowed package can refuse to wipe the data block based on the contents of
+     * the specified bundle. This bundle may contain data used by the allowed package to wipe the
+     * partition such as account credentials or an authorization token.
+     * @param bundle data used to wipe the data block. The contents of this bundle depend on the
+     *    allowed package receiving the data.
+     * @param pi intent called when attempt finished. The result code of this intent will be set
+     *    to one of {@link #STATUS_SUCCESS}, {@link #STATUS_ERROR_REMOTE_EXCEPTION},
+     *    {@link #STATUS_ERROR_NETWORK_ERROR}, or {@link #STATUS_ERROR_NOT_COMPLIANT}.
+     */
+    public void wipeIfAllowed(Bundle bundle, PendingIntent pi) {
+        if (pi == null) {
+            throw new NullPointerException();
+        }
+        try {
+            sService.wipeIfAllowed(bundle, pi);
+        } catch (RemoteException e) {
+            onError("wiping persistent partition");
+        }
+    }
+
+    /**
      * Writes a byte enabling or disabling the ability to "OEM unlock" the device.
      */
     public void setOemUnlockEnabled(boolean enabled) {
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index 4f4b2d5..7c90261 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -20,11 +20,13 @@
 import android.graphics.Bitmap;
 import android.os.Bundle;
 
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
+
 /**
  * @hide
  */
 oneway interface IVoiceInteractionSession {
-    void show(in Bundle sessionArgs, int flags);
+    void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback);
     void hide();
     void handleAssist(in Bundle assistData);
     void handleScreenshot(in Bitmap screenshot);
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 419b92b..fee0c75 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -82,6 +82,12 @@
      */
     public static final int START_WITH_SCREENSHOT = 1<<1;
 
+    /**
+     * Flag for use with {@link #showSession}: indicate that the session has been started from the
+     * system assist gesture.
+     */
+    public static final int START_SOURCE_ASSIST_GESTURE = 1<<2;
+
     IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() {
         @Override public void ready() {
             mHandler.sendEmptyMessage(MSG_READY);
diff --git a/core/java/android/service/voice/VoiceInteractionServiceInfo.java b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
index ebc7507..4bc97c9 100644
--- a/core/java/android/service/voice/VoiceInteractionServiceInfo.java
+++ b/core/java/android/service/voice/VoiceInteractionServiceInfo.java
@@ -43,6 +43,7 @@
     private String mSessionService;
     private String mRecognitionService;
     private String mSettingsActivity;
+    private boolean mSupportsAssistGesture;
 
     public VoiceInteractionServiceInfo(PackageManager pm, ComponentName comp)
             throws PackageManager.NameNotFoundException {
@@ -94,6 +95,9 @@
                     com.android.internal.R.styleable.VoiceInteractionService_recognitionService);
             mSettingsActivity = array.getString(
                     com.android.internal.R.styleable.VoiceInteractionService_settingsActivity);
+            mSupportsAssistGesture = array.getBoolean(
+                    com.android.internal.R.styleable.VoiceInteractionService_supportsAssistGesture,
+                    false);
             array.recycle();
             if (mSessionService == null) {
                 mParseError = "No sessionService specified";
@@ -103,11 +107,6 @@
                 mParseError = "No recognitionService specified";
                 return;
             }
-            /* Not yet time
-            if (mRecognitionService == null) {
-                mParseError = "No recogitionService specified";
-                return;
-            } */
         } catch (XmlPullParserException e) {
             mParseError = "Error parsing voice interation service meta-data: " + e;
             Log.w(TAG, "error parsing voice interaction service meta-data", e);
@@ -145,4 +144,8 @@
     public String getSettingsActivity() {
         return mSettingsActivity;
     }
+
+    public boolean getSupportsAssistGesture() {
+        return mSupportsAssistGesture;
+    }
 }
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 3245f55..20d7079 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -16,6 +16,7 @@
 
 package android.service.voice;
 
+import android.app.AssistStructure;
 import android.app.Dialog;
 import android.app.Instrumentation;
 import android.app.VoiceInteractor;
@@ -43,6 +44,7 @@
 import android.view.WindowManager;
 import android.widget.FrameLayout;
 import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.IVoiceInteractorCallback;
 import com.android.internal.app.IVoiceInteractorRequest;
@@ -163,9 +165,10 @@
 
     final IVoiceInteractionSession mSession = new IVoiceInteractionSession.Stub() {
         @Override
-        public void show(Bundle sessionArgs, int flags) {
-            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIO(MSG_SHOW,
-                    flags, sessionArgs));
+        public void show(Bundle sessionArgs, int flags,
+                IVoiceInteractionSessionShowCallback showCallback) {
+            mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageIOO(MSG_SHOW,
+                    flags, sessionArgs, showCallback));
         }
 
         @Override
@@ -175,6 +178,18 @@
 
         @Override
         public void handleAssist(Bundle assistBundle) {
+            // We want to pre-warm the AssistStructure before handing it off to the main
+            // thread.  There is a strong argument to be made that it should be handed
+            // through as a separate param rather than part of the assistBundle.
+            if (assistBundle != null) {
+                Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
+                if (assistContext != null) {
+                    AssistStructure as = AssistStructure.getAssistStructure(assistContext);
+                    if (as != null) {
+                        as.ensureData();
+                    }
+                }
+            }
             mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageO(MSG_HANDLE_ASSIST,
                     assistBundle));
         }
@@ -412,9 +427,12 @@
                     onHandleScreenshot((Bitmap) msg.obj);
                     break;
                 case MSG_SHOW:
-                    if (DEBUG) Log.d(TAG, "doShow: args=" + msg.obj
-                            + " flags=" + msg.arg1);
-                    doShow((Bundle) msg.obj, msg.arg1);
+                    args = (SomeArgs)msg.obj;
+                    if (DEBUG) Log.d(TAG, "doShow: args=" + args.arg1
+                            + " flags=" + msg.arg1
+                            + " showCallback=" + args.arg2);
+                    doShow((Bundle) args.arg1, msg.arg1,
+                            (IVoiceInteractionSessionShowCallback) args.arg2);
                     break;
                 case MSG_HIDE:
                     if (DEBUG) Log.d(TAG, "doHide");
@@ -502,6 +520,10 @@
                 mCallbacks, true);
     }
 
+    public Context getContext() {
+        return mContext;
+    }
+
     Request newRequest(IVoiceInteractorCallback callback) {
         synchronized (this) {
             Request req = new Request(callback, this);
@@ -523,7 +545,7 @@
         onCreate(args, startFlags);
     }
 
-    void doShow(Bundle args, int flags) {
+    void doShow(Bundle args, int flags, final IVoiceInteractionSessionShowCallback showCallback) {
         if (DEBUG) Log.v(TAG, "Showing window: mWindowAdded=" + mWindowAdded
                 + " mWindowVisible=" + mWindowVisible);
 
@@ -548,6 +570,22 @@
                 mWindowVisible = true;
                 mWindow.show();
             }
+            if (showCallback != null) {
+                mRootView.invalidate();
+                mRootView.getViewTreeObserver().addOnPreDrawListener(
+                        new ViewTreeObserver.OnPreDrawListener() {
+                            @Override
+                            public boolean onPreDraw() {
+                                mRootView.getViewTreeObserver().removeOnPreDrawListener(this);
+                                try {
+                                    showCallback.onShown();
+                                } catch (RemoteException e) {
+                                    Log.w(TAG, "Error calling onShown", e);
+                                }
+                                return true;
+                            }
+                        });
+            }
         } finally {
             mWindowWasVisible = true;
             mInShowWindow = false;
@@ -582,7 +620,8 @@
         mRootView = mInflater.inflate(
                 com.android.internal.R.layout.voice_interaction_session, null);
         mRootView.setSystemUiVisibility(
-                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+                View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
         mWindow.setContentView(mRootView);
         mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer);
 
@@ -716,7 +755,9 @@
         mWindow = new SoftInputWindow(mContext, "VoiceInteractionSession", mTheme,
                 mCallbacks, this, mDispatcherState,
                 WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true);
-        mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        mWindow.getWindow().addFlags(
+                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED |
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
         initViews();
         mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT);
         mWindow.setToken(mToken);
@@ -795,6 +836,12 @@
         return false;
     }
 
+    /**
+     * Called when the user presses the back button while focus is in the session UI.  Note
+     * that this will only happen if the session UI has requested input focus in its window;
+     * otherwise, the back key will go to whatever window has focus and do whatever behavior
+     * it normally has there.
+     */
     public void onBackPressed() {
         hide();
     }
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 7d2e1ef..239b386 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -79,7 +79,8 @@
                          boolean includepad,
                          TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
         this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
-                spacingmult, spacingadd, includepad, ellipsize, ellipsizedWidth);
+                spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
+                ellipsize, ellipsizedWidth);
     }
 
     /**
@@ -95,7 +96,7 @@
                          TextPaint paint,
                          int width, Alignment align, TextDirectionHeuristic textDir,
                          float spacingmult, float spacingadd,
-                         boolean includepad,
+                         boolean includepad, int breakStrategy,
                          TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
         super((ellipsize == null)
                 ? display
@@ -120,6 +121,7 @@
         mObjects = new PackedObjectVector<Directions>(1);
 
         mIncludePad = includepad;
+        mBreakStrategy = breakStrategy;
 
         /*
          * This is annoying, but we can't refer to the layout until
@@ -279,10 +281,9 @@
             sBuilder = null;
         }
 
-        // TODO: make sure reflowed is properly initialized
         if (reflowed == null) {
             reflowed = new StaticLayout(null);
-            b = StaticLayout.Builder.obtain();
+            b = StaticLayout.Builder.obtain(text, where, where + after, getWidth());
         }
 
         b.setText(text, where, where + after)
@@ -292,7 +293,8 @@
                 .setSpacingMult(getSpacingMultiplier())
                 .setSpacingAdd(getSpacingAdd())
                 .setEllipsizedWidth(mEllipsizedWidth)
-                .setEllipsize(mEllipsizeAt);
+                .setEllipsize(mEllipsizeAt)
+                .setBreakStrategy(mBreakStrategy);
         reflowed.generate(b, false, true);
         int n = reflowed.getLineCount();
 
@@ -717,6 +719,7 @@
     private boolean mEllipsize;
     private int mEllipsizedWidth;
     private TextUtils.TruncateAt mEllipsizeAt;
+    private int mBreakStrategy;
 
     private PackedIntVector mInts;
     private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index f4dff9b..a99bdf5 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -30,7 +30,7 @@
  *
  * @hide
  */
-/* package */ class Hyphenator {
+public class Hyphenator {
     // This class has deliberately simple lifetime management (no finalizer) because in
     // the common case a process will use a very small number of locales.
 
@@ -45,20 +45,14 @@
     }
 
     public static long get(Locale locale) {
-        synchronized (sMap) {
-            Hyphenator result = sMap.get(locale);
-            if (result == null) {
-                result = loadHyphenator(locale);
-                sMap.put(locale, result);
-            }
-            return result == null ? 0 : result.mNativePtr;
-        }
+        Hyphenator result = sMap.get(locale);
+        return result == null ? 0 : result.mNativePtr;
     }
 
     private static Hyphenator loadHyphenator(Locale locale) {
         // TODO: find pattern dictionary (from system location) that best matches locale
         if (Locale.US.equals(locale)) {
-            File f = new File("/data/local/tmp/hyph-en-us.pat.txt");
+            File f = new File(getSystemHyphenatorLocation(), "hyph-en-us.pat.txt");
             try {
                 RandomAccessFile rf = new RandomAccessFile(f, "r");
                 byte[] buf = new byte[(int)rf.length()];
@@ -68,9 +62,26 @@
                 long nativePtr = StaticLayout.nLoadHyphenator(patternData);
                 return new Hyphenator(nativePtr);
             } catch (IOException e) {
-                Log.e(TAG, "error loading hyphenation " + f);
+                Log.e(TAG, "error loading hyphenation " + f, e);
             }
         }
         return null;
     }
+
+    private static File getSystemHyphenatorLocation() {
+        // TODO: move to a sensible location under system
+        return new File("/system/usr/hyphen-data");
+    }
+
+    /**
+     * Load hyphenation patterns at initialization time. We want to have patterns
+     * for all locales loaded and ready to use so we don't have to do any file IO
+     * on the UI thread when drawing text in different locales.
+     *
+     * @hide
+     */
+    public static void init() {
+        Locale l = Locale.US;
+        sMap.put(l, loadHyphenator(l));
+    }
 }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 22abb18..60de02a 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.IntDef;
 import android.emoji.EmojiFactory;
 import android.graphics.Canvas;
 import android.graphics.Paint;
@@ -33,6 +34,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
 
 /**
@@ -43,6 +46,31 @@
  * For text that will not change, use a {@link StaticLayout}.
  */
 public abstract class Layout {
+    /** @hide */
+    @IntDef({BREAK_STRATEGY_SIMPLE, BREAK_STRATEGY_HIGH_QUALITY, BREAK_STRATEGY_BALANCED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BreakStrategy {}
+
+    /**
+     * Value for break strategy indicating simple line breaking. Automatic hyphens are not added
+     * (though soft hyphens are respected), and modifying text generally doesn't affect the layout
+     * before it (which yields a more consistent user experience when editing), but layout may not
+     * be the highest quality.
+     */
+    public static final int BREAK_STRATEGY_SIMPLE = 0;
+
+    /**
+     * Value for break strategy indicating high quality line breaking, including automatic
+     * hyphenation and doing whole-paragraph optimization of line breaks.
+     */
+    public static final int BREAK_STRATEGY_HIGH_QUALITY = 1;
+
+    /**
+     * Value for break strategy indicating balanced line breaking. The breaks are chosen to
+     * make all lines as close to the same length as possible, including automatic hyphenation.
+     */
+    public static final int BREAK_STRATEGY_BALANCED = 2;
+
     private static final ParagraphStyle[] NO_PARA_SPANS =
         ArrayUtils.emptyArray(ParagraphStyle.class);
 
@@ -355,6 +383,7 @@
                 tl.set(paint, buf, start, end, dir, directions, hasTabOrEmoji, tabStops);
                 tl.draw(canvas, x, ltop, lbaseline, lbottom);
             }
+            paint.setHyphenEdit(0);
         }
 
         TextLine.recycle(tl);
diff --git a/core/java/android/text/SpanSet.java b/core/java/android/text/SpanSet.java
index 3ca6033..00f1493 100644
--- a/core/java/android/text/SpanSet.java
+++ b/core/java/android/text/SpanSet.java
@@ -17,6 +17,7 @@
 package android.text;
 
 import java.lang.reflect.Array;
+import java.util.Arrays;
 
 /**
  * A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then
@@ -54,6 +55,7 @@
             spanFlags = new int[length];
         }
 
+        int prevNumberOfSpans = numberOfSpans;
         numberOfSpans = 0;
         for (int i = 0; i < length; i++) {
             final E span = allSpans[i];
@@ -71,6 +73,12 @@
 
             numberOfSpans++;
         }
+
+        // cleanup extra spans left over from previous init() call
+        if (numberOfSpans < prevNumberOfSpans) {
+            // prevNumberofSpans was > 0, therefore spans != null
+            Arrays.fill(spans, numberOfSpans, prevNumberOfSpans, null);
+        }
     }
 
     /**
@@ -103,9 +111,8 @@
      * Removes all internal references to the spans to avoid memory leaks.
      */
     public void recycle() {
-        // The spans array is guaranteed to be not null when numberOfSpans is > 0
-        for (int i = 0; i < numberOfSpans; i++) {
-            spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled
+        if (spans != null) {
+            Arrays.fill(spans, 0, numberOfSpans, null);
         }
     }
 }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 4174df0..2bcb352 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -23,6 +23,7 @@
 import android.text.style.MetricAffectingSpan;
 import android.text.style.TabStopSpan;
 import android.util.Log;
+import android.util.Pools.SynchronizedPool;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
@@ -56,28 +57,23 @@
             mNativePtr = nNewBuilder();
         }
 
-        static Builder obtain() {
-            Builder b = null;
-            synchronized (sLock) {
-                for (int i = 0; i < sCached.length; i++) {
-                    if (sCached[i] != null) {
-                        b = sCached[i];
-                        sCached[i] = null;
-                        break;
-                    }
-                }
-            }
+        public static Builder obtain(CharSequence source, int start, int end, int width) {
+            Builder b = sPool.acquire();
             if (b == null) {
                 b = new Builder();
             }
 
             // set default initial values
-            b.mWidth = 0;
+            b.mText = source;
+            b.mStart = start;
+            b.mEnd = end;
+            b.mWidth = width;
+            b.mAlignment = Alignment.ALIGN_NORMAL;
             b.mTextDir = TextDirectionHeuristics.FIRSTSTRONG_LTR;
             b.mSpacingMult = 1.0f;
             b.mSpacingAdd = 0.0f;
             b.mIncludePad = true;
-            b.mEllipsizedWidth = 0;
+            b.mEllipsizedWidth = width;
             b.mEllipsize = null;
             b.mMaxLines = Integer.MAX_VALUE;
 
@@ -85,18 +81,11 @@
             return b;
         }
 
-        static void recycle(Builder b) {
+        private static void recycle(Builder b) {
             b.mPaint = null;
             b.mText = null;
             MeasuredText.recycle(b.mMeasuredText);
-            synchronized (sLock) {
-                for (int i = 0; i < sCached.length; i++) {
-                    if (sCached[i] == null) {
-                        sCached[i] = b;
-                        break;
-                    }
-                }
-            }
+            sPool.release(b);
         }
 
         // release any expensive state
@@ -129,6 +118,11 @@
             return this;
         }
 
+        public Builder setAlignment(Alignment alignment) {
+            mAlignment = alignment;
+            return this;
+        }
+
         public Builder setTextDir(TextDirectionHeuristic textDir) {
             mTextDir = textDir;
             return this;
@@ -166,6 +160,11 @@
             return this;
         }
 
+        public Builder setBreakStrategy(@BreakStrategy int breakStrategy) {
+            mBreakStrategy = breakStrategy;
+            return this;
+        }
+
         /**
          * Measurement and break iteration is done in native code. The protocol for using
          * the native code is as follows.
@@ -207,10 +206,8 @@
         }
 
         public StaticLayout build() {
-            // TODO: can optimize based on whether ellipsis is needed
-            StaticLayout result = new StaticLayout(mText);
-            result.generate(this, this.mIncludePad, this.mIncludePad);
-            recycle(this);
+            StaticLayout result = new StaticLayout(this);
+            Builder.recycle(this);
             return result;
         }
 
@@ -230,6 +227,7 @@
         int mEnd;
         TextPaint mPaint;
         int mWidth;
+        Alignment mAlignment;
         TextDirectionHeuristic mTextDir;
         float mSpacingMult;
         float mSpacingAdd;
@@ -237,6 +235,7 @@
         int mEllipsizedWidth;
         TextUtils.TruncateAt mEllipsize;
         int mMaxLines;
+        int mBreakStrategy;
 
         Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
 
@@ -245,8 +244,7 @@
 
         Locale mLocale;
 
-        private static final Object sLock = new Object();
-        private static final Builder[] sCached = new Builder[3];
+        private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<Builder>(3);
     }
 
     public StaticLayout(CharSequence source, TextPaint paint,
@@ -316,10 +314,9 @@
                     : new Ellipsizer(source),
               paint, outerwidth, align, textDir, spacingmult, spacingadd);
 
-        Builder b = Builder.obtain();
-        b.setText(source, bufstart, bufend)
+        Builder b = Builder.obtain(source, bufstart, bufend, outerwidth)
             .setPaint(paint)
-            .setWidth(outerwidth)
+            .setAlignment(align)
             .setTextDir(textDir)
             .setSpacingMult(spacingmult)
             .setSpacingAdd(spacingadd)
@@ -366,6 +363,35 @@
         mLines = new int[mLineDirections.length];
     }
 
+    private StaticLayout(Builder b) {
+        super((b.mEllipsize == null)
+                ? b.mText
+                : (b.mText instanceof Spanned)
+                    ? new SpannedEllipsizer(b.mText)
+                    : new Ellipsizer(b.mText),
+                b.mPaint, b.mWidth, b.mAlignment, b.mSpacingMult, b.mSpacingAdd);
+
+        if (b.mEllipsize != null) {
+            Ellipsizer e = (Ellipsizer) getText();
+
+            e.mLayout = this;
+            e.mWidth = b.mEllipsizedWidth;
+            e.mMethod = b.mEllipsize;
+            mEllipsizedWidth = b.mEllipsizedWidth;
+
+            mColumns = COLUMNS_ELLIPSIZE;
+        } else {
+            mColumns = COLUMNS_NORMAL;
+            mEllipsizedWidth = b.mWidth;
+        }
+
+        mLineDirections = ArrayUtils.newUnpaddedArray(Directions.class, 2 * mColumns);
+        mLines = new int[mLineDirections.length];
+        mMaximumVisibleLineCount = b.mMaxLines;
+
+        generate(b, b.mIncludePad, b.mIncludePad);
+    }
+
     /* package */ void generate(Builder b, boolean includepad, boolean trackpad) {
         CharSequence source = b.mText;
         int bufStart = b.mStart;
@@ -477,10 +503,9 @@
                 }
             }
 
-            int breakStrategy = 0;  // 0 = kBreakStrategy_Greedy
             nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
                     firstWidth, firstWidthLineCount, restWidth,
-                    variableTabStops, TAB_INCREMENT, breakStrategy);
+                    variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
 
             // measurement has to be done before performing line breaking
             // but we don't want to recompute fontmetrics or span ranges the
diff --git a/core/java/android/text/method/AllCapsTransformationMethod.java b/core/java/android/text/method/AllCapsTransformationMethod.java
index f9920dd..0cea821 100644
--- a/core/java/android/text/method/AllCapsTransformationMethod.java
+++ b/core/java/android/text/method/AllCapsTransformationMethod.java
@@ -19,6 +19,7 @@
 import android.graphics.Rect;
 import android.util.Log;
 import android.view.View;
+import android.widget.TextView;
 
 import java.util.Locale;
 
@@ -39,11 +40,23 @@
 
     @Override
     public CharSequence getTransformation(CharSequence source, View view) {
-        if (mEnabled) {
-            return source != null ? source.toString().toUpperCase(mLocale) : null;
+        if (!mEnabled) {
+            Log.w(TAG, "Caller did not enable length changes; not transforming text");
+            return source;
         }
-        Log.w(TAG, "Caller did not enable length changes; not transforming text");
-        return source;
+
+        if (source == null) {
+            return null;
+        }
+
+        Locale locale = null;
+        if (view instanceof TextView) {
+            locale = ((TextView)view).getTextLocale();
+        }
+        if (locale == null) {
+            locale = mLocale;
+        }
+        return source.toString().toUpperCase(locale);
     }
 
     @Override
diff --git a/core/java/android/text/method/BaseKeyListener.java b/core/java/android/text/method/BaseKeyListener.java
index 63607fa..07c1ec3 100644
--- a/core/java/android/text/method/BaseKeyListener.java
+++ b/core/java/android/text/method/BaseKeyListener.java
@@ -22,6 +22,8 @@
 import android.text.method.TextKeyListener.Capitalize;
 import android.widget.TextView;
 
+import java.text.BreakIterator;
+
 /**
  * Abstract base class for key listeners.
  *
@@ -63,9 +65,9 @@
 
     private boolean backspaceOrForwardDelete(View view, Editable content, int keyCode,
             KeyEvent event, boolean isForwardDelete) {
-        // Ensure the key event does not have modifiers except ALT or SHIFT.
+        // Ensure the key event does not have modifiers except ALT or SHIFT or CTRL.
         if (!KeyEvent.metaStateHasNoModifiers(event.getMetaState()
-                & ~(KeyEvent.META_SHIFT_MASK | KeyEvent.META_ALT_MASK))) {
+                & ~(KeyEvent.META_SHIFT_MASK | KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK))) {
             return false;
         }
 
@@ -74,18 +76,28 @@
             return true;
         }
 
-        // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
-        if (getMetaState(content, META_ALT_ON, event) == 1) {
-            if (deleteLine(view, content)) {
-                return true;
+        // MetaKeyKeyListener doesn't track control key state. Need to check the KeyEvent instead.
+        boolean isCtrlActive = ((event.getMetaState() & KeyEvent.META_CTRL_ON) != 0);
+        boolean isShiftActive = (getMetaState(content, META_SHIFT_ON, event) == 1);
+        boolean isAltActive = (getMetaState(content, META_ALT_ON, event) == 1);
+
+        if (isCtrlActive) {
+            if (isAltActive || isShiftActive) {
+                // Ctrl+Alt, Ctrl+Shift, Ctrl+Alt+Shift should not delete any characters.
+                return false;
             }
+            return deleteUntilWordBoundary(view, content, isForwardDelete);
+        }
+
+        // Alt+Backspace or Alt+ForwardDelete deletes the current line, if possible.
+        if (isAltActive && deleteLine(view, content)) {
+            return true;
         }
 
         // Delete a character.
         final int start = Selection.getSelectionEnd(content);
         final int end;
-        if (isForwardDelete || event.isShiftPressed()
-                || getMetaState(content, META_SHIFT_ON) == 1) {
+        if (isForwardDelete || event.isShiftPressed() || isShiftActive) {
             end = TextUtils.getOffsetAfter(content, start);
         } else {
             end = TextUtils.getOffsetBefore(content, start);
@@ -97,6 +109,54 @@
         return false;
     }
 
+    private boolean deleteUntilWordBoundary(View view, Editable content, boolean isForwardDelete) {
+        int currentCursorOffset = Selection.getSelectionStart(content);
+
+        // If there is a selection, do nothing.
+        if (currentCursorOffset != Selection.getSelectionEnd(content)) {
+            return false;
+        }
+
+        // Early exit if there is no contents to delete.
+        if ((!isForwardDelete && currentCursorOffset == 0) ||
+            (isForwardDelete && currentCursorOffset == content.length())) {
+            return false;
+        }
+
+        WordIterator wordIterator = null;
+        if (view instanceof TextView) {
+            wordIterator = ((TextView)view).getWordIterator();
+        }
+
+        if (wordIterator == null) {
+            // Default locale is used for WordIterator since the appropriate locale is not clear
+            // here.
+            // TODO: Use appropriate locale for WordIterator.
+            wordIterator = new WordIterator();
+        }
+
+        int deleteFrom;
+        int deleteTo;
+
+        if (isForwardDelete) {
+            deleteFrom = currentCursorOffset;
+            wordIterator.setCharSequence(content, deleteFrom, content.length());
+            deleteTo = wordIterator.following(currentCursorOffset);
+            if (deleteTo == BreakIterator.DONE) {
+                deleteTo = content.length();
+            }
+        } else {
+            deleteTo = currentCursorOffset;
+            wordIterator.setCharSequence(content, 0, deleteTo);
+            deleteFrom = wordIterator.preceding(currentCursorOffset);
+            if (deleteFrom == BreakIterator.DONE) {
+                deleteFrom = 0;
+            }
+        }
+        content.delete(deleteFrom, deleteTo);
+        return true;
+    }
+
     private boolean deleteSelection(View view, Editable content) {
         int selectionStart = Selection.getSelectionStart(content);
         int selectionEnd = Selection.getSelectionEnd(content);
diff --git a/core/java/android/transition/Fade.java b/core/java/android/transition/Fade.java
index e7857c0..287c696 100644
--- a/core/java/android/transition/Fade.java
+++ b/core/java/android/transition/Fade.java
@@ -108,7 +108,7 @@
     /**
      * Utility method to handle creating and running the Animator.
      */
-    private Animator createAnimation(View view, float startAlpha, float endAlpha) {
+    private Animator createAnimation(final View view, float startAlpha, final float endAlpha) {
         if (startAlpha == endAlpha) {
             return null;
         }
@@ -117,9 +117,15 @@
         if (DBG) {
             Log.d(LOG_TAG, "Created animator " + anim);
         }
-        FadeAnimatorListener listener = new FadeAnimatorListener(view);
+        final FadeAnimatorListener listener = new FadeAnimatorListener(view);
         anim.addListener(listener);
         anim.addPauseListener(listener);
+        addListener(new TransitionListenerAdapter() {
+            @Override
+            public void onTransitionEnd(Transition transition) {
+                view.setTransitionAlpha(1);
+            }
+        });
         return anim;
     }
 
@@ -143,7 +149,6 @@
 
     private static class FadeAnimatorListener extends AnimatorListenerAdapter {
         private final View mView;
-        private boolean mCanceled = false;
         private float mPausedAlpha = -1;
         private boolean mLayerTypeChanged = false;
 
@@ -160,18 +165,8 @@
         }
 
         @Override
-        public void onAnimationCancel(Animator animator) {
-            mCanceled = true;
-            if (mPausedAlpha >= 0) {
-                mView.setTransitionAlpha(mPausedAlpha);
-            }
-        }
-
-        @Override
         public void onAnimationEnd(Animator animator) {
-            if (!mCanceled) {
-                mView.setTransitionAlpha(1);
-            }
+            mView.setTransitionAlpha(1);
             if (mLayerTypeChanged) {
                 mView.setLayerType(View.LAYER_TYPE_NONE, null);
             }
diff --git a/core/java/android/transition/TransitionManager.java b/core/java/android/transition/TransitionManager.java
index 0b70fdb..5209f90 100644
--- a/core/java/android/transition/TransitionManager.java
+++ b/core/java/android/transition/TransitionManager.java
@@ -430,7 +430,6 @@
      * Ends all pending and ongoing transitions on the specified scene root.
      *
      * @param sceneRoot The root of the View hierarchy to end transitions on.
-     * @hide
      */
     public static void endTransitions(final ViewGroup sceneRoot) {
         sPendingTransitions.remove(sceneRoot);
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 36d5b50..8b57d3d 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -20,7 +20,7 @@
 
 /**
  * A class that contains utility methods related to numbers.
- * 
+ *
  * @hide Pending API council approval
  */
 public final class MathUtils {
@@ -32,7 +32,7 @@
     }
 
     public static float abs(float v) {
-        return v > 0 ? v : -v; 
+        return v > 0 ? v : -v;
     }
 
     public static int constrain(int amount, int low, int high) {
@@ -116,6 +116,14 @@
         return v * v;
     }
 
+    public static float dot(float v1x, float v1y, float v2x, float v2y) {
+        return v1x * v2x + v1y * v2y;
+    }
+
+    public static float cross(float v1x, float v1y, float v2x, float v2y) {
+        return v1x * v2y - v1y * v2x;
+    }
+
     public static float radians(float degrees) {
         return degrees * DEG_TO_RAD;
     }
@@ -142,16 +150,16 @@
 
     public static float tan(float angle) {
         return (float) Math.tan(angle);
-    }    
+    }
 
     public static float lerp(float start, float stop, float amount) {
         return start + (stop - start) * amount;
     }
-    
+
     public static float norm(float start, float stop, float value) {
         return (value - start) / (stop - start);
     }
-    
+
     public static float map(float minStart, float minStop, float maxStart, float maxStop, float value) {
         return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
     }
@@ -164,7 +172,7 @@
         if (howsmall >= howbig) return howsmall;
         return (int) (sRandom.nextFloat() * (howbig - howsmall) + howsmall);
     }
-    
+
     public static float random(float howbig) {
         return sRandom.nextFloat() * howbig;
     }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index c8149d9..79a8489 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -71,7 +71,12 @@
  */
 public final class Choreographer {
     private static final String TAG = "Choreographer";
-    private static final boolean DEBUG = false;
+
+    // Prints debug messages about jank which was detected (low volume).
+    private static final boolean DEBUG_JANK = false;
+
+    // Prints debug messages about every frame and callback registered (high volume).
+    private static final boolean DEBUG_FRAMES = false;
 
     // The default amount of time in ms between animation frames.
     // When vsync is not enabled, we want to have some idea of how long we should
@@ -139,6 +144,7 @@
     private boolean mCallbacksRunning;
     private long mLastFrameTimeNanos;
     private long mFrameIntervalNanos;
+    private boolean mDebugPrintNextFrameTimeDelta;
 
     /**
      * Contains information about the current frame for jank-tracking,
@@ -166,13 +172,25 @@
     public static final int CALLBACK_ANIMATION = 1;
 
     /**
-     * Callback type: Traversal callback.  Handles layout and draw.  Runs last
+     * Callback type: Traversal callback.  Handles layout and draw.  Runs
      * after all other asynchronous messages have been handled.
      * @hide
      */
     public static final int CALLBACK_TRAVERSAL = 2;
 
-    private static final int CALLBACK_LAST = CALLBACK_TRAVERSAL;
+    /**
+     * Callback type: Commit callback.  Handles post-draw operations for the frame.
+     * Runs after traversal completes.  The {@link #getFrameTime() frame time} reported
+     * during this callback may be updated to reflect delays that occurred while
+     * traversals were in progress in case heavy layout operations caused some frames
+     * to be skipped.  The frame time reported during this callback provides a better
+     * estimate of the start time of the frame in which animations (and other updates
+     * to the view hierarchy state) actually took effect.
+     * @hide
+     */
+    public static final int CALLBACK_COMMIT = 3;
+
+    private static final int CALLBACK_LAST = CALLBACK_COMMIT;
 
     private Choreographer(Looper looper) {
         mLooper = looper;
@@ -332,7 +350,7 @@
 
     private void postCallbackDelayedInternal(int callbackType,
             Object action, Object token, long delayMillis) {
-        if (DEBUG) {
+        if (DEBUG_FRAMES) {
             Log.d(TAG, "PostCallback: type=" + callbackType
                     + ", action=" + action + ", token=" + token
                     + ", delayMillis=" + delayMillis);
@@ -376,7 +394,7 @@
     }
 
     private void removeCallbacksInternal(int callbackType, Object action, Object token) {
-        if (DEBUG) {
+        if (DEBUG_FRAMES) {
             Log.d(TAG, "RemoveCallbacks: type=" + callbackType
                     + ", action=" + action + ", token=" + token);
         }
@@ -492,7 +510,7 @@
         if (!mFrameScheduled) {
             mFrameScheduled = true;
             if (USE_VSYNC) {
-                if (DEBUG) {
+                if (DEBUG_FRAMES) {
                     Log.d(TAG, "Scheduling next frame on vsync.");
                 }
 
@@ -509,7 +527,7 @@
             } else {
                 final long nextFrameTime = Math.max(
                         mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
-                if (DEBUG) {
+                if (DEBUG_FRAMES) {
                     Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
                 }
                 Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
@@ -526,6 +544,12 @@
                 return; // no work to do
             }
 
+            if (DEBUG_JANK && mDebugPrintNextFrameTimeDelta) {
+                mDebugPrintNextFrameTimeDelta = false;
+                Log.d(TAG, "Frame time delta: "
+                        + ((frameTimeNanos - mLastFrameTimeNanos) * 0.000001f) + " ms");
+            }
+
             long intendedFrameTimeNanos = frameTimeNanos;
             startNanos = System.nanoTime();
             final long jitterNanos = startNanos - frameTimeNanos;
@@ -536,7 +560,7 @@
                             + "The application may be doing too much work on its main thread.");
                 }
                 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos;
-                if (DEBUG) {
+                if (DEBUG_JANK) {
                     Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms "
                             + "which is more than the frame interval of "
                             + (mFrameIntervalNanos * 0.000001f) + " ms!  "
@@ -547,7 +571,7 @@
             }
 
             if (frameTimeNanos < mLastFrameTimeNanos) {
-                if (DEBUG) {
+                if (DEBUG_JANK) {
                     Log.d(TAG, "Frame time appears to be going backwards.  May be due to a "
                             + "previously skipped frame.  Waiting for next vsync.");
                 }
@@ -569,7 +593,9 @@
         mFrameInfo.markPerformTraversalsStart();
         doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
 
-        if (DEBUG) {
+        doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+
+        if (DEBUG_FRAMES) {
             final long endNanos = System.nanoTime();
             Log.d(TAG, "Frame " + frame + ": Finished, took "
                     + (endNanos - startNanos) * 0.000001f + " ms, latency "
@@ -583,16 +609,43 @@
             // We use "now" to determine when callbacks become due because it's possible
             // for earlier processing phases in a frame to post callbacks that should run
             // in a following phase, such as an input event that causes an animation to start.
-            final long now = SystemClock.uptimeMillis();
-            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
+            final long now = System.nanoTime();
+            callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
+                    now / TimeUtils.NANOS_PER_MS);
             if (callbacks == null) {
                 return;
             }
             mCallbacksRunning = true;
+
+            // Update the frame time if necessary when committing the frame.
+            // We only update the frame time if we are more than 2 frames late reaching
+            // the commit phase.  This ensures that the frame time which is observed by the
+            // callbacks will always increase from one frame to the next and never repeat.
+            // We never want the next frame's starting frame time to end up being less than
+            // or equal to the previous frame's commit frame time.  Keep in mind that the
+            // next frame has most likely already been scheduled by now so we play it
+            // safe by ensuring the commit time is always at least one frame behind.
+            if (callbackType == Choreographer.CALLBACK_COMMIT) {
+                final long jitterNanos = now - frameTimeNanos;
+                if (jitterNanos >= 2 * mFrameIntervalNanos) {
+                    final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
+                            + mFrameIntervalNanos;
+                    if (DEBUG_JANK) {
+                        Log.d(TAG, "Commit callback delayed by " + (jitterNanos * 0.000001f)
+                                + " ms which is more than twice the frame interval of "
+                                + (mFrameIntervalNanos * 0.000001f) + " ms!  "
+                                + "Setting frame time to " + (lastFrameOffset * 0.000001f)
+                                + " ms in the past.");
+                        mDebugPrintNextFrameTimeDelta = true;
+                    }
+                    frameTimeNanos = now - lastFrameOffset;
+                    mLastFrameTimeNanos = frameTimeNanos;
+                }
+            }
         }
         try {
             for (CallbackRecord c = callbacks; c != null; c = c.next) {
-                if (DEBUG) {
+                if (DEBUG_FRAMES) {
                     Log.d(TAG, "RunCallback: type=" + callbackType
                             + ", action=" + c.action + ", token=" + c.token
                             + ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 3caf6f0..ec8f802 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -48,7 +48,6 @@
     private int mWidth;
     private int mHeight;
 
-
     static DisplayListCanvas obtain(@NonNull RenderNode node) {
         if (node == null) throw new IllegalArgumentException("node cannot be null");
         DisplayListCanvas canvas = sPool.acquire();
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 2eac549..1ee47802 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -49,7 +49,6 @@
     private final String mName;
     private final int mVendorId;
     private final int mProductId;
-    private final String mUniqueId;
     private final String mDescriptor;
     private final InputDeviceIdentifier mIdentifier;
     private final boolean mIsExternal;
@@ -57,6 +56,7 @@
     private final int mKeyboardType;
     private final KeyCharacterMap mKeyCharacterMap;
     private final boolean mHasVibrator;
+    private final boolean mHasMic;
     private final boolean mHasButtonUnderPad;
     private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>();
 
@@ -357,8 +357,8 @@
 
     // Called by native code.
     private InputDevice(int id, int generation, int controllerNumber, String name, int vendorId,
-            int productId, String uniqueId, String descriptor, boolean isExternal, int sources,
-            int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator,
+            int productId, String descriptor, boolean isExternal, int sources, int keyboardType,
+            KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMic,
             boolean hasButtonUnderPad) {
         mId = id;
         mGeneration = generation;
@@ -366,13 +366,13 @@
         mName = name;
         mVendorId = vendorId;
         mProductId = productId;
-        mUniqueId = uniqueId;
         mDescriptor = descriptor;
         mIsExternal = isExternal;
         mSources = sources;
         mKeyboardType = keyboardType;
         mKeyCharacterMap = keyCharacterMap;
         mHasVibrator = hasVibrator;
+        mHasMic = hasMic;
         mHasButtonUnderPad = hasButtonUnderPad;
         mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId);
     }
@@ -384,13 +384,13 @@
         mName = in.readString();
         mVendorId = in.readInt();
         mProductId = in.readInt();
-        mUniqueId = in.readString();
         mDescriptor = in.readString();
         mIsExternal = in.readInt() != 0;
         mSources = in.readInt();
         mKeyboardType = in.readInt();
         mKeyCharacterMap = KeyCharacterMap.CREATOR.createFromParcel(in);
         mHasVibrator = in.readInt() != 0;
+        mHasMic = in.readInt() != 0;
         mHasButtonUnderPad = in.readInt() != 0;
         mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId);
 
@@ -509,23 +509,6 @@
     }
 
     /**
-     * Gets the vendor's unique id for the given device, if available.
-     * <p>
-     * A vendor may assign a unique id to a device (e.g., MAC address for
-     * Bluetooth devices). A null value will be assigned where a unique id is
-     * not available.
-     * </p><p>
-     * This method is dependent on the vendor, whereas {@link #getDescriptor}
-     * attempts to create a unique id even when the vendor has not provided one.
-     * </p>
-     *
-     * @return The unique id of a given device
-     */
-    public String getUniqueId() {
-        return mUniqueId;
-    }
-
-    /**
      * Gets the input device descriptor, which is a stable identifier for an input device.
      * <p>
      * An input device descriptor uniquely identifies an input device.  Its value
@@ -737,6 +720,14 @@
     }
 
     /**
+     * Reports whether the device has a built-in microphone.
+     * @return Whether the device has a built-in microphone.
+     */
+    public boolean hasMic() {
+        return mHasMic;
+    }
+
+    /**
      * Reports whether the device has a button under its touchpad
      * @return Whether the device has a button under its touchpad
      * @hide
@@ -864,13 +855,13 @@
         out.writeString(mName);
         out.writeInt(mVendorId);
         out.writeInt(mProductId);
-        out.writeString(mUniqueId);
         out.writeString(mDescriptor);
         out.writeInt(mIsExternal ? 1 : 0);
         out.writeInt(mSources);
         out.writeInt(mKeyboardType);
         mKeyCharacterMap.writeToParcel(out, flags);
         out.writeInt(mHasVibrator ? 1 : 0);
+        out.writeInt(mHasMic ? 1 : 0);
         out.writeInt(mHasButtonUnderPad ? 1 : 0);
 
         final int numRanges = mMotionRanges.size();
@@ -916,6 +907,8 @@
 
         description.append("  Has Vibrator: ").append(mHasVibrator).append("\n");
 
+        description.append("  Has mic: ").append(mHasMic).append("\n");
+
         description.append("  Sources: 0x").append(Integer.toHexString(mSources)).append(" (");
         appendSourceDescriptionIfApplicable(description, SOURCE_KEYBOARD, "keyboard");
         appendSourceDescriptionIfApplicable(description, SOURCE_DPAD, "dpad");
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index cb32697..38f4d1c 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -29,6 +29,7 @@
 
 import com.android.internal.R;
 import com.android.internal.util.ScreenShapeHelper;
+import com.android.internal.view.FloatingActionMode;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
@@ -41,6 +42,7 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.DecorContentParent;
+import com.android.internal.widget.FloatingToolbar;
 import com.android.internal.widget.SwipeDismissLayout;
 
 import android.app.ActivityManager;
@@ -2179,6 +2181,9 @@
         private ActionBarContextView mPrimaryActionModeView;
         private PopupWindow mPrimaryActionModePopup;
         private Runnable mShowPrimaryActionModePopup;
+        private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
+        private View mFloatingActionModeOriginatingView;
+        private FloatingToolbar mFloatingToolbar;
 
         // View added at runtime to draw under the status bar area
         private View mStatusGuard;
@@ -2703,18 +2708,18 @@
                 if (mode.getType() == ActionMode.TYPE_PRIMARY) {
                     cleanupPrimaryActionMode();
                     mPrimaryActionMode = mode;
-                } else {
+                } else if (mode.getType() == ActionMode.TYPE_FLOATING) {
+                    if (mFloatingActionMode != null) {
+                        mFloatingActionMode.finish();
+                    }
                     mFloatingActionMode = mode;
                 }
             } else {
-                if (type == ActionMode.TYPE_PRIMARY) {
-                    cleanupPrimaryActionMode();
-                    mode = createStandaloneActionMode(wrappedCallback);
-                    if (mode != null && callback.onCreateActionMode(mode, mode.getMenu())) {
-                        setHandledPrimaryActionMode(mode);
-                    } else {
-                        mode = null;
-                    }
+                mode = createActionMode(type, wrappedCallback, originatingView);
+                if (mode != null && wrappedCallback.onCreateActionMode(mode, mode.getMenu())) {
+                    setHandledActionMode(mode);
+                } else {
+                    mode = null;
                 }
             }
             if (mode != null && getCallback() != null && !isDestroyed()) {
@@ -2737,6 +2742,21 @@
             }
         }
 
+        private void cleanupFloatingActionModeViews() {
+            if (mFloatingToolbar != null) {
+                mFloatingToolbar.dismiss();
+                mFloatingToolbar = null;
+            }
+            if (mFloatingActionModeOriginatingView != null) {
+                if (mFloatingToolbarPreDrawListener != null) {
+                    mFloatingActionModeOriginatingView.getViewTreeObserver()
+                        .removeOnPreDrawListener(mFloatingToolbarPreDrawListener);
+                    mFloatingToolbarPreDrawListener = null;
+                }
+                mFloatingActionModeOriginatingView = null;
+            }
+        }
+
         public void startChanging() {
             mChanging = true;
         }
@@ -3128,6 +3148,14 @@
             if (cb != null && !isDestroyed() && mFeatureId < 0) {
                 cb.onWindowFocusChanged(hasWindowFocus);
             }
+
+            if (mFloatingToolbar != null) {
+                if (hasWindowFocus) {
+                    mFloatingToolbar.show();
+                } else {
+                    mFloatingToolbar.dismiss();
+                }
+            }
         }
 
         void updateWindowResizeState() {
@@ -3179,6 +3207,10 @@
                 }
                 mPrimaryActionModePopup = null;
             }
+            if (mFloatingToolbar != null) {
+                mFloatingToolbar.dismiss();
+                mFloatingToolbar = null;
+            }
 
             PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
             if (st != null && st.menu != null && mFeatureId < 0) {
@@ -3220,7 +3252,27 @@
             updateColorViewTranslations();
         }
 
+        private ActionMode createActionMode(
+                int type, ActionMode.Callback2 callback, View originatingView) {
+            switch (type) {
+                case ActionMode.TYPE_PRIMARY:
+                default:
+                    return createStandaloneActionMode(callback);
+                case ActionMode.TYPE_FLOATING:
+                    return createFloatingActionMode(originatingView, callback);
+            }
+        }
+
+        private void setHandledActionMode(ActionMode mode) {
+            if (mode.getType() == ActionMode.TYPE_PRIMARY) {
+                setHandledPrimaryActionMode(mode);
+            } else if (mode.getType() == ActionMode.TYPE_FLOATING) {
+                setHandledFloatingActionMode(mode);
+            }
+        }
+
         private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
+            cleanupPrimaryActionMode();
             if (mPrimaryActionModeView == null) {
                 if (isFloating()) {
                     // Use the action bar theme.
@@ -3291,6 +3343,35 @@
                     AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
         }
 
+        private ActionMode createFloatingActionMode(
+                View originatingView, ActionMode.Callback2 callback) {
+            if (mFloatingActionMode != null) {
+                mFloatingActionMode.finish();
+            }
+            cleanupFloatingActionModeViews();
+            mFloatingToolbar = new FloatingToolbar(mContext, PhoneWindow.this);
+            final FloatingActionMode mode = new FloatingActionMode(
+                    mContext, callback, originatingView, mFloatingToolbar);
+            mFloatingActionModeOriginatingView = originatingView;
+            mFloatingToolbarPreDrawListener =
+                new ViewTreeObserver.OnPreDrawListener() {
+                    @Override
+                    public boolean onPreDraw() {
+                        mode.updateViewLocationInWindow();
+                        return true;
+                    }
+                };
+            return mode;
+        }
+
+        private void setHandledFloatingActionMode(ActionMode mode) {
+            mFloatingActionMode = mode;
+            mFloatingActionMode.invalidate();
+            mFloatingToolbar.show();
+            mFloatingActionModeOriginatingView.getViewTreeObserver()
+                .addOnPreDrawListener(mFloatingToolbarPreDrawListener);
+        }
+
         /**
          * Clears out internal references when the action mode is destroyed.
          */
@@ -3328,6 +3409,7 @@
                     }
                     mPrimaryActionMode = null;
                 } else if (mode == mFloatingActionMode) {
+                    cleanupFloatingActionModeViews();
                     mFloatingActionMode = null;
                 }
                 if (getCallback() != null && !isDestroyed()) {
@@ -3339,6 +3421,15 @@
                 }
                 requestFitSystemWindows();
             }
+
+            @Override
+            public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
+                if (mWrapped instanceof ActionMode.Callback2) {
+                    ((ActionMode.Callback2) mWrapped).onGetContentRect(mode, view, outRect);
+                } else {
+                    super.onGetContentRect(mode, view, outRect);
+                }
+            }
         }
     }
 
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index ef98bbc..236cfef 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -240,12 +240,7 @@
      * @see #start(int, int)
      * @see #isValid()
      */
-    public void end(DisplayListCanvas endCanvas) {
-        if (!(endCanvas instanceof DisplayListCanvas)) {
-            throw new IllegalArgumentException("Passed an invalid canvas to end!");
-        }
-
-        DisplayListCanvas canvas = (DisplayListCanvas) endCanvas;
+    public void end(DisplayListCanvas canvas) {
         canvas.onPostDraw();
         long renderNodeData = canvas.finishRecording();
         nSetDisplayListData(mNativeRenderNode, renderNodeData);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a69384a..b6f1e3b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -91,6 +91,7 @@
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.widget.Checkable;
 import android.widget.ScrollBarDrawable;
 
 import static android.os.Build.VERSION_CODES.*;
@@ -3582,6 +3583,8 @@
             // of whether a layout was requested on that View.
             sIgnoreMeasureCache = targetSdkVersion < KITKAT;
 
+            Canvas.sCompatibilityRestore = targetSdkVersion < MNC;
+
             sCompatibilityDone = true;
         }
     }
@@ -5676,10 +5679,143 @@
     /**
      * Called when assist structure is being retrieved from a view as part of
      * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
-     * @param structure Additional standard structured view structure to supply.
-     * @param extras Non-standard extensions.
+     * @param structure Fill in with structured view data.  The default implementation
+     * fills in all data that can be inferred from the view itself.
      */
-    public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) {
+    public void onProvideAssistStructure(ViewAssistStructure structure) {
+        final int id = mID;
+        if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
+                && (id&0x0000ffff) != 0) {
+            String pkg, type, entry;
+            try {
+                final Resources res = getResources();
+                entry = res.getResourceEntryName(id);
+                type = res.getResourceTypeName(id);
+                pkg = res.getResourcePackageName(id);
+            } catch (Resources.NotFoundException e) {
+                entry = type = pkg = null;
+            }
+            structure.setId(id, pkg, type, entry);
+        } else {
+            structure.setId(id, null, null, null);
+        }
+        structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight-mLeft, mBottom-mTop);
+        structure.setVisibility(getVisibility());
+        structure.setEnabled(isEnabled());
+        if (isClickable()) {
+            structure.setClickable(true);
+        }
+        if (isFocusable()) {
+            structure.setFocusable(true);
+        }
+        if (isFocused()) {
+            structure.setFocused(true);
+        }
+        if (isAccessibilityFocused()) {
+            structure.setAccessibilityFocused(true);
+        }
+        if (isSelected()) {
+            structure.setSelected(true);
+        }
+        if (isActivated()) {
+            structure.setActivated(true);
+        }
+        if (isLongClickable()) {
+            structure.setLongClickable(true);
+        }
+        if (this instanceof Checkable) {
+            structure.setCheckable(true);
+            if (((Checkable)this).isChecked()) {
+                structure.setChecked(true);
+            }
+        }
+        structure.setClassName(getAccessibilityClassName().toString());
+        structure.setContentDescription(getContentDescription());
+    }
+
+    /**
+     * Called when assist structure is being retrieved from a view as part of
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to
+     * generate additional virtual structure under this view.  The defaullt implementation
+     * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the
+     * view's virtual accessibility nodes, if any.  You can override this for a more
+     * optimal implementation providing this data.
+     */
+    public void onProvideVirtualAssistStructure(ViewAssistStructure structure) {
+        AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
+        if (provider != null) {
+            AccessibilityNodeInfo info = createAccessibilityNodeInfo();
+            Log.i("View", "Provider of " + this + ": children=" + info.getChildCount());
+            structure.setChildCount(1);
+            ViewAssistStructure root = structure.newChild(0);
+            populateVirtualAssistStructure(root, provider, info);
+            info.recycle();
+        }
+    }
+
+    private void populateVirtualAssistStructure(ViewAssistStructure structure,
+            AccessibilityNodeProvider provider, AccessibilityNodeInfo info) {
+        structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
+                null, null, null);
+        Rect rect = structure.getTempRect();
+        info.getBoundsInParent(rect);
+        structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height());
+        structure.setVisibility(VISIBLE);
+        structure.setEnabled(info.isEnabled());
+        if (info.isClickable()) {
+            structure.setClickable(true);
+        }
+        if (info.isFocusable()) {
+            structure.setFocusable(true);
+        }
+        if (info.isFocused()) {
+            structure.setFocused(true);
+        }
+        if (info.isAccessibilityFocused()) {
+            structure.setAccessibilityFocused(true);
+        }
+        if (info.isSelected()) {
+            structure.setSelected(true);
+        }
+        if (info.isLongClickable()) {
+            structure.setLongClickable(true);
+        }
+        if (info.isCheckable()) {
+            structure.setCheckable(true);
+            if (info.isChecked()) {
+                structure.setChecked(true);
+            }
+        }
+        CharSequence cname = info.getClassName();
+        structure.setClassName(cname != null ? cname.toString() : null);
+        structure.setContentDescription(info.getContentDescription());
+        Log.i("View", "vassist " + cname + " @ " + rect.toShortString()
+                + " text=" + info.getText() + " cd=" + info.getContentDescription());
+        if (info.getText() != null || info.getError() != null) {
+            structure.setText(info.getText(), info.getTextSelectionStart(),
+                    info.getTextSelectionEnd());
+        }
+        final int NCHILDREN = info.getChildCount();
+        if (NCHILDREN > 0) {
+            structure.setChildCount(NCHILDREN);
+            for (int i=0; i<NCHILDREN; i++) {
+                AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
+                        AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
+                ViewAssistStructure child = structure.newChild(i);
+                populateVirtualAssistStructure(child, provider, cinfo);
+                cinfo.recycle();
+            }
+        }
+    }
+
+    /**
+     * Dispatch creation of {@link ViewAssistStructure} down the hierarchy.  The default
+     * implementation calls {@link #onProvideAssistStructure} and
+     * {@link #onProvideVirtualAssistStructure}.
+     */
+    public void dispatchProvideAssistStructure(ViewAssistStructure structure) {
+        onProvideAssistStructure(structure);
+        onProvideVirtualAssistStructure(structure);
     }
 
     /**
@@ -8264,7 +8400,7 @@
                     return true;
                 }
             } break;
-            case R.id.accessibility_action_show_on_screen: {
+            case R.id.accessibilityActionShowOnScreen: {
                 if (mAttachInfo != null) {
                     final Rect r = mAttachInfo.mTmpInvalRect;
                     getDrawingRect(r);
@@ -16782,7 +16918,7 @@
     @Nullable
     public ColorStateList getForegroundTintList() {
         return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
-                ? mBackgroundTint.mTintList : null;
+                ? mForegroundInfo.mTintInfo.mTintList : null;
     }
 
     /**
diff --git a/core/java/android/view/ViewAssistStructure.java b/core/java/android/view/ViewAssistStructure.java
index 5132bb9..7d263c5 100644
--- a/core/java/android/view/ViewAssistStructure.java
+++ b/core/java/android/view/ViewAssistStructure.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.graphics.Rect;
+import android.os.Bundle;
 import android.text.TextPaint;
 
 /**
@@ -23,6 +25,37 @@
  * View.onProvideAssistStructure}.
  */
 public abstract class ViewAssistStructure {
+    public abstract void setId(int id, String packageName, String typeName, String entryName);
+
+    public abstract void setDimens(int left, int top, int scrollX, int scrollY, int width,
+            int height);
+
+    public abstract void setVisibility(int visibility);
+
+    public abstract void setEnabled(boolean state);
+
+    public abstract void setClickable(boolean state);
+
+    public abstract void setLongClickable(boolean state);
+
+    public abstract void setFocusable(boolean state);
+
+    public abstract void setFocused(boolean state);
+
+    public abstract void setAccessibilityFocused(boolean state);
+
+    public abstract void setCheckable(boolean state);
+
+    public abstract void setChecked(boolean state);
+
+    public abstract void setSelected(boolean state);
+
+    public abstract void setActivated(boolean state);
+
+    public abstract void setClassName(String className);
+
+    public abstract void setContentDescription(CharSequence contentDescription);
+
     public abstract void setText(CharSequence text);
     public abstract void setText(CharSequence text, int selectionStart, int selectionEnd);
     public abstract void setTextPaint(TextPaint paint);
@@ -32,4 +65,17 @@
     public abstract int getTextSelectionStart();
     public abstract int getTextSelectionEnd();
     public abstract CharSequence getHint();
+
+    public abstract Bundle editExtras();
+    public abstract void clearExtras();
+
+    public abstract void setChildCount(int num);
+    public abstract int getChildCount();
+    public abstract ViewAssistStructure newChild(int index);
+
+    public abstract ViewAssistStructure asyncNewChild(int index);
+    public abstract void asyncCommit();
+
+    /** @hide */
+    public abstract Rect getTempRect();
 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 87f3e94..d0705bb 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2852,6 +2852,33 @@
         return false;
     }
 
+    /**
+     * Dispatch creation of {@link ViewAssistStructure} down the hierarchy.  This implementation
+     * adds in all child views of the view group, in addition to calling the default View
+     * implementation.
+     */
+    public void dispatchProvideAssistStructure(ViewAssistStructure structure) {
+        super.dispatchProvideAssistStructure(structure);
+        if (structure.getChildCount() == 0) {
+            final int childrenCount = getChildCount();
+            if (childrenCount > 0) {
+                structure.setChildCount(childrenCount);
+                final ArrayList<View> preorderedList = buildOrderedChildList();
+                final boolean customOrder = preorderedList == null
+                        && isChildrenDrawingOrderEnabled();
+                final View[] children = mChildren;
+                for (int i=0; i<childrenCount; i++) {
+                    final int childIndex = customOrder
+                            ? getChildDrawingOrder(childrenCount, i) : i;
+                    final View child = (preorderedList == null)
+                            ? children[childIndex] : preorderedList.get(childIndex);
+                    ViewAssistStructure cstructure = structure.newChild(i);
+                    child.dispatchProvideAssistStructure(cstructure);
+                }
+            }
+        }
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
@@ -5727,12 +5754,12 @@
             } else if (childDimension == LayoutParams.MATCH_PARENT) {
                 // Child wants to be our size... find out how big it should
                 // be
-                resultSize = 0;
+                resultSize = size;
                 resultMode = MeasureSpec.UNSPECIFIED;
             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                 // Child wants to determine its own size.... find out how
                 // big it should be
-                resultSize = 0;
+                resultSize = size;
                 resultMode = MeasureSpec.UNSPECIFIED;
             }
             break;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 66dae7b..54d78f3 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -223,6 +223,7 @@
             @ViewDebug.IntToString(from = TYPE_MAGNIFICATION_OVERLAY, to = "TYPE_MAGNIFICATION_OVERLAY"),
             @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"),
             @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"),
+            @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
         })
         public int type;
     
@@ -549,6 +550,12 @@
         public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
 
         /**
+         * Window type: Starting window for voice interaction layer.
+         * @hide
+         */
+        public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 77082b0..0736ed8 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -266,7 +266,8 @@
      * Action to set the selection. Performing this action with no arguments
      * clears the selection.
      * <p>
-     * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SELECTION_START_INT},
+     * <strong>Arguments:</strong>
+     * {@link #ACTION_ARGUMENT_SELECTION_START_INT},
      * {@link #ACTION_ARGUMENT_SELECTION_END_INT}<br>
      * <strong>Example:</strong>
      * <code><pre><p>
@@ -302,7 +303,8 @@
      * null</code> or empty {@link CharSequence} will clear the text. This action will also put the
      * cursor at the end of text.
      * <p>
-     * <strong>Arguments:</strong> {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
+     * <strong>Arguments:</strong>
+     * {@link #ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE}<br>
      * <strong>Example:</strong>
      * <code><pre><p>
      *   Bundle arguments = new Bundle();
@@ -326,12 +328,15 @@
      * Argument for which movement granularity to be used when traversing the node text.
      * <p>
      * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
-     * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
+     *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
+     * </ul>
      * </p>
      *
-     * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-     * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+     * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+     * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
      */
     public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT =
             "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
@@ -340,12 +345,15 @@
      * Argument for which HTML element to get moving to the next/previous HTML element.
      * <p>
      * <strong>Type:</strong> String<br>
-     * <strong>Actions:</strong> {@link #ACTION_NEXT_HTML_ELEMENT},
-     *         {@link #ACTION_PREVIOUS_HTML_ELEMENT}
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_NEXT_HTML_ELEMENT}</li>
+     *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT}</li>
+     * </ul>
      * </p>
      *
-     * @see #ACTION_NEXT_HTML_ELEMENT
-     * @see #ACTION_PREVIOUS_HTML_ELEMENT
+     * @see AccessibilityAction#ACTION_NEXT_HTML_ELEMENT
+     * @see AccessibilityAction#ACTION_PREVIOUS_HTML_ELEMENT
      */
     public static final String ACTION_ARGUMENT_HTML_ELEMENT_STRING =
             "ACTION_ARGUMENT_HTML_ELEMENT_STRING";
@@ -355,12 +363,14 @@
      * or to move it otherwise.
      * <p>
      * <strong>Type:</strong> boolean<br>
-     * <strong>Actions:</strong> {@link #ACTION_NEXT_AT_MOVEMENT_GRANULARITY},
-     * {@link #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}
-     * </p>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY}</li>
+     *     <li>{@link AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY}</li>
+     * </ul>
      *
-     * @see #ACTION_NEXT_AT_MOVEMENT_GRANULARITY
-     * @see #ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
+     * @see AccessibilityAction#ACTION_NEXT_AT_MOVEMENT_GRANULARITY
+     * @see AccessibilityAction#ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY
      */
     public static final String ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN =
             "ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
@@ -369,10 +379,12 @@
      * Argument for specifying the selection start.
      * <p>
      * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
-     * </p>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
+     * </ul>
      *
-     * @see #ACTION_SET_SELECTION
+     * @see AccessibilityAction#ACTION_SET_SELECTION
      */
     public static final String ACTION_ARGUMENT_SELECTION_START_INT =
             "ACTION_ARGUMENT_SELECTION_START_INT";
@@ -381,26 +393,58 @@
      * Argument for specifying the selection end.
      * <p>
      * <strong>Type:</strong> int<br>
-     * <strong>Actions:</strong> {@link #ACTION_SET_SELECTION}
-     * </p>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_SET_SELECTION}</li>
+     * </ul>
      *
-     * @see #ACTION_SET_SELECTION
+     * @see AccessibilityAction#ACTION_SET_SELECTION
      */
     public static final String ACTION_ARGUMENT_SELECTION_END_INT =
             "ACTION_ARGUMENT_SELECTION_END_INT";
 
     /**
-     * Argument for specifying the text content to set
+     * Argument for specifying the text content to set.
      * <p>
      * <strong>Type:</strong> CharSequence<br>
-     * <strong>Actions:</strong> {@link #ACTION_SET_TEXT}
-     * </p>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_SET_TEXT}</li>
+     * </ul>
      *
-     * @see #ACTION_SET_TEXT
+     * @see AccessibilityAction#ACTION_SET_TEXT
      */
     public static final String ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE =
             "ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE";
 
+    /**
+     * Argument for specifying the collection row to make visible on screen.
+     * <p>
+     * <strong>Type:</strong> int<br>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
+     * </ul>
+     *
+     * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
+     */
+    public static final String ACTION_ARGUMENT_ROW_INT =
+            "android.view.accessibility.action.ARGUMENT_ROW_INT";
+
+    /**
+     * Argument for specifying the collection column to make visible on screen.
+     * <p>
+     * <strong>Type:</strong> int<br>
+     * <strong>Actions:</strong>
+     * <ul>
+     *     <li>{@link AccessibilityAction#ACTION_SCROLL_TO_POSITION}</li>
+     * </ul>
+     *
+     * @see AccessibilityAction#ACTION_SCROLL_TO_POSITION
+     */
+    public static final String ACTION_ARGUMENT_COLUMN_INT =
+            "android.view.accessibility.action.ARGUMENT_COLUMN_INT";
+
     // Focus types
 
     /**
@@ -539,7 +583,7 @@
     // Housekeeping.
     private static final int MAX_POOL_SIZE = 50;
     private static final SynchronizedPool<AccessibilityNodeInfo> sPool =
-            new SynchronizedPool<AccessibilityNodeInfo>(MAX_POOL_SIZE);
+            new SynchronizedPool<>(MAX_POOL_SIZE);
 
     private boolean mSealed;
 
@@ -970,7 +1014,7 @@
         }
 
         if (mActions == null) {
-            mActions = new ArrayList<AccessibilityAction>();
+            mActions = new ArrayList<>();
         }
 
         mActions.remove(action);
@@ -1562,7 +1606,7 @@
     }
 
     /**
-     * Sets whether this node is visible to the user.
+     * Gets whether this node is visible to the user.
      *
      * @return Whether the node is visible to the user.
      */
@@ -3411,9 +3455,24 @@
          * @see View#requestRectangleOnScreen(Rect)
          */
         public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
-                new AccessibilityAction(R.id.accessibility_action_show_on_screen, null);
+                new AccessibilityAction(R.id.accessibilityActionShowOnScreen, null);
 
-        private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>();
+        /**
+         * Action that scrolls the node to make the specified collection
+         * position visible on screen.
+         * <p>
+         * <strong>Arguments:</strong>
+         * <ul>
+         *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_ROW_INT}</li>
+         *     <li>{@link AccessibilityNodeInfo#ACTION_ARGUMENT_COLUMN_INT}</li>
+         * <ul>
+         *
+         * @see AccessibilityNodeInfo#getCollectionInfo()
+         */
+        public static final AccessibilityAction ACTION_SCROLL_TO_POSITION =
+                new AccessibilityAction(R.id.accessibilityActionScrollToPosition, null);
+
+        private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<>();
         static {
             sStandardActions.add(ACTION_FOCUS);
             sStandardActions.add(ACTION_CLEAR_FOCUS);
@@ -3438,6 +3497,7 @@
             sStandardActions.add(ACTION_DISMISS);
             sStandardActions.add(ACTION_SET_TEXT);
             sStandardActions.add(ACTION_SHOW_ON_SCREEN);
+            sStandardActions.add(ACTION_SCROLL_TO_POSITION);
         }
 
         private final int mActionId;
@@ -3658,7 +3718,7 @@
         private static final int MAX_POOL_SIZE = 20;
 
         private static final SynchronizedPool<CollectionInfo> sPool =
-                new SynchronizedPool<CollectionInfo>(MAX_POOL_SIZE);
+                new SynchronizedPool<>(MAX_POOL_SIZE);
 
         private int mRowCount;
         private int mColumnCount;
@@ -3804,7 +3864,7 @@
         private static final int MAX_POOL_SIZE = 20;
 
         private static final SynchronizedPool<CollectionItemInfo> sPool =
-                new SynchronizedPool<CollectionItemInfo>(MAX_POOL_SIZE);
+                new SynchronizedPool<>(MAX_POOL_SIZE);
 
         /**
          * Obtains a pooled instance that is a clone of another one.
diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java
index 4d1209a..0417921 100644
--- a/core/java/android/view/animation/AnimationUtils.java
+++ b/core/java/android/view/animation/AnimationUtils.java
@@ -16,6 +16,7 @@
 
 package android.view.animation;
 
+import android.content.res.Configuration;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -44,6 +45,16 @@
     private static final int TOGETHER = 0;
     private static final int SEQUENTIALLY = 1;
 
+    private static final float RECOMMENDED_FIELD_OF_VIEW_FOR_TV = 40f;
+    private static final float ESTIMATED_VIEWING_DISTANCE_FOR_WATCH = 11f;
+    private static final float AVERAGE_VIEWING_DISTANCE_FOR_PHONES = 14.2f;
+    private static final float N5_DIAGONAL_VIEW_ANGLE = 19.58f;
+    private static final float N5_DENSITY = 3.0f;
+    private static final float N5_DPI = 443f;
+
+    private static final float COTANGENT_OF_HALF_TV_ANGLE = (float)  (1 / Math.tan(Math.toRadians
+                (RECOMMENDED_FIELD_OF_VIEW_FOR_TV / 2)));
+
 
     /**
      * Returns the current animation time in milliseconds. This time should be used when invoking
@@ -367,4 +378,78 @@
         }
         return interpolator;
     }
+
+    /**
+     * Derives the viewing distance of a device based on the device size (in inches), and the
+     * device type.
+     * @hide
+     */
+    public static float getViewingDistance(float width, float height, int uiMode) {
+        if (uiMode == Configuration.UI_MODE_TYPE_TELEVISION) {
+            // TV
+            return (width / 2) * COTANGENT_OF_HALF_TV_ANGLE;
+        } else if (uiMode == Configuration.UI_MODE_TYPE_WATCH) {
+            // Watch
+            return ESTIMATED_VIEWING_DISTANCE_FOR_WATCH;
+        } else {
+            // Tablet, phone, etc
+            return AVERAGE_VIEWING_DISTANCE_FOR_PHONES;
+        }
+    }
+
+    /**
+     * Calculates the duration scaling factor of an animation based on the hint that the animation
+     * will move across the entire screen. A scaling factor of 1 means the duration on this given
+     * device will be the same as the duration set through
+     * {@link android.animation.Animator#setDuration(long)}. The calculation uses Nexus 5 as a
+     * baseline device. That is, the duration of the animation on a given device will scale its
+     * duration so that it has the same look and feel as the animation on Nexus 5. In order to
+     * achieve the same perceived effect of the animation across different devices, we maintain
+     * the same angular speed of the same animation in users' field of view. Therefore, the
+     * duration scale factor is determined by the ratio of the angular movement on current
+     * devices to that on the baseline device.
+     *
+     * @param width width of the screen (in inches)
+     * @param height height of the screen (in inches)
+     * @param viewingDistance the viewing distance of the device (i.e. watch, phone, TV, etc) in
+     *                        inches
+     * @return scaling factor (or multiplier) of the duration set through
+     * {@link android.animation.Animator#setDuration(long)} on current device.
+     * @hide
+     */
+    public static float getScreenSizeBasedDurationScale(float width, float height,
+            float viewingDistance) {
+        // Animation's moving distance is proportional to the screen size.
+        float diagonal = (float) Math.sqrt(width * width + height * height);
+        float diagonalViewAngle = (float) Math.toDegrees(Math.atan((diagonal / 2f)
+                / viewingDistance) * 2);
+        return diagonalViewAngle / N5_DIAGONAL_VIEW_ANGLE;
+    }
+
+    /**
+     * Calculates the duration scaling factor of an animation under the assumption that the
+     * animation is defined to move the same amount of distance (in dp) across all devices. A
+     * scaling factor of 1 means the duration on this given device will be the same as the
+     * duration set through {@link android.animation.Animator#setDuration(long)}. The calculation
+     * uses Nexus 5 as a baseline device. That is, the duration of the animation on a given
+     * device will scale its duration so that it has the same look and feel as the animation on
+     * Nexus 5. In order to achieve the same perceived effect of the animation across different
+     * devices, we maintain the same angular velocity of the same animation in users' field of
+     * view. Therefore, the duration scale factor is determined by the ratio of the angular
+     * movement on current devices to that on the baseline device.
+     *
+     * @param density logical density of the display. {@link android.util.DisplayMetrics#density}
+     * @param dpi pixels per inch
+     * @param viewingDistance viewing distance of the device (in inches)
+     * @return the scaling factor of duration
+     * @hide
+     */
+    public static float getDpBasedDurationScale(float density, float dpi,
+            float viewingDistance) {
+        // Angle in users' field of view per dp:
+        float anglePerDp = (float) Math.atan2((density / dpi) / 2, viewingDistance) * 2;
+        float baselineAnglePerDp = (float) Math.atan2((N5_DENSITY / N5_DPI) / 2,
+                AVERAGE_VIEWING_DISTANCE_FOR_PHONES) * 2;
+        return anglePerDp / baselineAnglePerDp;
+    }
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index aa77d5e..e7c4328 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -40,6 +40,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewAssistStructure;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
@@ -2424,6 +2425,13 @@
         return WebView.class.getName();
     }
 
+    @Override
+    public void onProvideVirtualAssistStructure(ViewAssistStructure structure) {
+        super.onProvideVirtualAssistStructure(structure);
+        // TODO: enable when chromium backend lands.
+        // mProvider.getViewDelegate().onProvideVirtualAssistStructure(structure);
+    }
+
     /** @hide */
     @Override
     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index fa2ce1b..d5787de 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -32,6 +32,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewAssistStructure;
 import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -298,6 +299,8 @@
     interface ViewDelegate {
         public boolean shouldDelayChildPressedState();
 
+        public void onProvideVirtualAssistStructure(ViewAssistStructure structure);
+
         public AccessibilityNodeProvider getAccessibilityNodeProvider();
 
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 168066a..e7b6238 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -61,6 +61,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
@@ -1504,11 +1505,11 @@
         super.onInitializeAccessibilityNodeInfoInternal(info);
         if (isEnabled()) {
             if (canScrollUp()) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
+                info.addAction(AccessibilityAction.ACTION_SCROLL_BACKWARD);
                 info.setScrollable(true);
             }
             if (canScrollDown()) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+                info.addAction(AccessibilityAction.ACTION_SCROLL_FORWARD);
                 info.setScrollable(true);
             }
         }
@@ -2502,18 +2503,18 @@
 
         if (position == getSelectedItemPosition()) {
             info.setSelected(true);
-            info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION);
+            info.addAction(AccessibilityAction.ACTION_CLEAR_SELECTION);
         } else {
-            info.addAction(AccessibilityNodeInfo.ACTION_SELECT);
+            info.addAction(AccessibilityAction.ACTION_SELECT);
         }
 
         if (isClickable()) {
-            info.addAction(AccessibilityNodeInfo.ACTION_CLICK);
+            info.addAction(AccessibilityAction.ACTION_CLICK);
             info.setClickable(true);
         }
 
         if (isLongClickable()) {
-            info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
+            info.addAction(AccessibilityAction.ACTION_LONG_CLICK);
             info.setLongClickable(true);
         }
     }
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 4fadc19..f951dc2 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -16,6 +16,10 @@
 
 package android.widget;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
@@ -24,6 +28,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.view.ActionProvider;
 import android.view.Gravity;
@@ -32,6 +37,7 @@
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ListPopupWindow.ForwardingListener;
 import com.android.internal.transition.ActionBarTransition;
@@ -45,6 +51,7 @@
 import com.android.internal.view.menu.SubMenuBuilder;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * MenuPresenter for building action menus as seen in the action bar and action modes.
@@ -54,6 +61,7 @@
 public class ActionMenuPresenter extends BaseMenuPresenter
         implements ActionProvider.SubUiVisibilityListener {
     private static final String TAG = "ActionMenuPresenter";
+    private static final int ITEM_ANIMATION_DURATION = 150;
 
     private OverflowMenuButton mOverflowButton;
     private boolean mReserveOverflow;
@@ -71,8 +79,6 @@
     // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
     private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
 
-    private View mScrapActionButtonView;
-
     private OverflowPopup mOverflowPopup;
     private ActionButtonSubmenu mActionButtonPopup;
 
@@ -84,6 +90,18 @@
     final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
     int mOpenSubMenuId;
 
+    // These collections are used to store pre- and post-layout information for menu items,
+    // which is used to determine appropriate animations to run for changed items.
+    private SparseArray<MenuItemLayoutInfo> mPreLayoutItems =
+            new SparseArray<MenuItemLayoutInfo>();
+    private SparseArray<MenuItemLayoutInfo> mPostLayoutItems =
+            new SparseArray<MenuItemLayoutInfo>();
+
+    // The list of currently running animations on menu items.
+    private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>();
+
+
+
     public ActionMenuPresenter(Context context) {
         super(context, com.android.internal.R.layout.action_menu_layout,
                 com.android.internal.R.layout.action_menu_item_layout);
@@ -125,9 +143,6 @@
         mActionItemWidthLimit = width;
 
         mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
-
-        // Drop a scrap view as it may no longer reflect the proper context/config.
-        mScrapActionButtonView = null;
     }
 
     public void onConfigurationChanged(Configuration newConfig) {
@@ -202,10 +217,187 @@
         return item.isActionButton();
     }
 
+    /**
+     * Store layout information about current items in the menu. This is stored for
+     * both pre- and post-layout phases and compared in runItemAnimations() to determine
+     * the animations that need to be run on any item changes.
+     *
+     * @param preLayout Whether this is being called in the pre-layout phase. This is passed
+     * into the MenuItemLayoutInfo structure to store the appropriate position values.
+     */
+    private void computeMenuItemAnimationInfo(boolean preLayout) {
+        final ViewGroup menuViewParent = (ViewGroup) mMenuView;
+        final int count = menuViewParent.getChildCount();
+        SparseArray items = preLayout ? mPreLayoutItems : mPostLayoutItems;
+        for (int i = 0; i < count; ++i) {
+            View child = menuViewParent.getChildAt(i);
+            final int id = child.getId();
+            if (id > 0 && child.getWidth() != 0 && child.getHeight() != 0) {
+                MenuItemLayoutInfo info = new MenuItemLayoutInfo(child, preLayout);
+                items.put(id, info);
+            }
+        }
+    }
+
+    /**
+     * This method is called once both the pre-layout and post-layout steps have
+     * happened. It figures out which views are new (didn't exist prior to layout),
+     * gone (existed pre-layout, but are now gone), or changed (exist in both,
+     * but in a different location) and runs appropriate animations on those views.
+     * Items are tracked by ids, since the underlying views that represent items
+     * pre- and post-layout may be different.
+     */
+    private void runItemAnimations() {
+        for (int i = 0; i < mPreLayoutItems.size(); ++i) {
+            int id = mPreLayoutItems.keyAt(i);
+            final MenuItemLayoutInfo menuItemLayoutInfoPre = mPreLayoutItems.get(id);
+            final int postLayoutIndex = mPostLayoutItems.indexOfKey(id);
+            if (postLayoutIndex >= 0) {
+                // item exists pre and post: see if it's changed
+                final MenuItemLayoutInfo menuItemLayoutInfoPost =
+                        mPostLayoutItems.valueAt(postLayoutIndex);
+                PropertyValuesHolder pvhX = null;
+                PropertyValuesHolder pvhY = null;
+                if (menuItemLayoutInfoPre.left != menuItemLayoutInfoPost.left) {
+                    pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X,
+                            (menuItemLayoutInfoPre.left - menuItemLayoutInfoPost.left), 0);
+                }
+                if (menuItemLayoutInfoPre.top != menuItemLayoutInfoPost.top) {
+                    pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y,
+                            menuItemLayoutInfoPre.top - menuItemLayoutInfoPost.top, 0);
+                }
+                if (pvhX != null || pvhY != null) {
+                    for (int j = 0; j < mRunningItemAnimations.size(); ++j) {
+                        ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j);
+                        if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.MOVE) {
+                            oldInfo.animator.cancel();
+                        }
+                    }
+                    ObjectAnimator anim;
+                    if (pvhX != null) {
+                        if (pvhY != null) {
+                            anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view,
+                                    pvhX, pvhY);
+                        } else {
+                            anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhX);
+                        }
+                    } else {
+                        anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhY);
+                    }
+                    anim.setDuration(ITEM_ANIMATION_DURATION);
+                    anim.start();
+                    ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfoPost, anim,
+                            ItemAnimationInfo.MOVE);
+                    mRunningItemAnimations.add(info);
+                    anim.addListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            for (int j = 0; j < mRunningItemAnimations.size(); ++j) {
+                                if (mRunningItemAnimations.get(j).animator == animation) {
+                                    mRunningItemAnimations.remove(j);
+                                    break;
+                                }
+                            }
+                        }
+                    });
+                }
+                mPostLayoutItems.remove(id);
+            } else {
+                // item used to be there, is now gone
+                float oldAlpha = 1;
+                for (int j = 0; j < mRunningItemAnimations.size(); ++j) {
+                    ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j);
+                    if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.FADE_IN) {
+                        oldAlpha = oldInfo.menuItemLayoutInfo.view.getAlpha();
+                        oldInfo.animator.cancel();
+                    }
+                }
+                ObjectAnimator anim = ObjectAnimator.ofFloat(menuItemLayoutInfoPre.view, View.ALPHA,
+                        oldAlpha, 0);
+                // Re-using the view from pre-layout assumes no view recycling
+                ((ViewGroup) mMenuView).getOverlay().add(menuItemLayoutInfoPre.view);
+                anim.setDuration(ITEM_ANIMATION_DURATION);
+                anim.start();
+                ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfoPre, anim, ItemAnimationInfo.FADE_OUT);
+                mRunningItemAnimations.add(info);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        for (int j = 0; j < mRunningItemAnimations.size(); ++j) {
+                            if (mRunningItemAnimations.get(j).animator == animation) {
+                                mRunningItemAnimations.remove(j);
+                                break;
+                            }
+                        }
+                        ((ViewGroup) mMenuView).getOverlay().remove(menuItemLayoutInfoPre.view);
+                    }
+                });
+            }
+        }
+        for (int i = 0; i < mPostLayoutItems.size(); ++i) {
+            int id = mPostLayoutItems.keyAt(i);
+            final int postLayoutIndex = mPostLayoutItems.indexOfKey(id);
+            if (postLayoutIndex >= 0) {
+                // item is new
+                final MenuItemLayoutInfo menuItemLayoutInfo =
+                        mPostLayoutItems.valueAt(postLayoutIndex);
+                float oldAlpha = 0;
+                for (int j = 0; j < mRunningItemAnimations.size(); ++j) {
+                    ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j);
+                    if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.FADE_OUT) {
+                        oldAlpha = oldInfo.menuItemLayoutInfo.view.getAlpha();
+                        oldInfo.animator.cancel();
+                    }
+                }
+                ObjectAnimator anim = ObjectAnimator.ofFloat(menuItemLayoutInfo.view, View.ALPHA,
+                        oldAlpha, 1);
+                anim.start();
+                anim.setDuration(ITEM_ANIMATION_DURATION);
+                ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfo, anim, ItemAnimationInfo.FADE_IN);
+                mRunningItemAnimations.add(info);
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        for (int j = 0; j < mRunningItemAnimations.size(); ++j) {
+                            if (mRunningItemAnimations.get(j).animator == animation) {
+                                mRunningItemAnimations.remove(j);
+                                break;
+                            }
+                        }
+                    }
+                });
+            }
+        }
+        mPreLayoutItems.clear();
+        mPostLayoutItems.clear();
+    }
+
+    /**
+     * Gets position/existence information on menu items before and after layout,
+     * which is then fed into runItemAnimations()
+     */
+    private void setupItemAnimations() {
+        final ViewGroup menuViewParent = (ViewGroup) mMenuView;
+        computeMenuItemAnimationInfo(true);
+        final ViewTreeObserver observer = menuViewParent.getViewTreeObserver();
+        if (observer != null) {
+            observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+                @Override
+                public boolean onPreDraw() {
+                    computeMenuItemAnimationInfo(false);
+                    observer.removeOnPreDrawListener(this);
+                    runItemAnimations();
+                    return true;
+                }
+            });
+        }
+    }
+
     @Override
     public void updateMenuView(boolean cleared) {
         final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent();
         if (menuViewParent != null) {
+//            setupItemAnimations();
             ActionBarTransition.beginDelayedTransition(menuViewParent);
         }
         super.updateMenuView(cleared);
@@ -431,10 +623,7 @@
             MenuItemImpl item = visibleItems.get(i);
 
             if (item.requiresActionButton()) {
-                View v = getItemView(item, mScrapActionButtonView, parent);
-                if (mScrapActionButtonView == null) {
-                    mScrapActionButtonView = v;
-                }
+                View v = getItemView(item, null, parent);
                 if (mStrictWidthLimit) {
                     cellsRemaining -= ActionMenuView.measureChildForCells(v,
                             cellSize, cellsRemaining, querySpec, 0);
@@ -460,10 +649,7 @@
                         (!mStrictWidthLimit || cellsRemaining > 0);
 
                 if (isAction) {
-                    View v = getItemView(item, mScrapActionButtonView, parent);
-                    if (mScrapActionButtonView == null) {
-                        mScrapActionButtonView = v;
-                    }
+                    View v = getItemView(item, null, parent);
                     if (mStrictWidthLimit) {
                         final int cells = ActionMenuView.measureChildForCells(v,
                                 cellSize, cellsRemaining, querySpec, 0);
@@ -819,4 +1005,53 @@
         boolean mHasTintMode;
         boolean mHasTintList;
     }
+
+    /**
+     * This class holds layout information for a menu item. This is used to determine
+     * pre- and post-layout information about menu items, which will then be used to
+     * determine appropriate item animations.
+     */
+    private static class MenuItemLayoutInfo {
+        View view;
+        int left;
+        int top;
+
+        MenuItemLayoutInfo(View view, boolean preLayout) {
+            left = view.getLeft();
+            top = view.getTop();
+            if (preLayout) {
+                // We track translation for pre-layout because a view might be mid-animation
+                // and we need this information to know where to animate from
+                left += view.getTranslationX();
+                top += view.getTranslationY();
+            }
+            this.view = view;
+        }
+    }
+
+    /**
+     * This class is used to store information about currently-running item animations.
+     * This is used when new animations are scheduled to determine whether any existing
+     * animations need to be canceled, based on whether the running animations overlap
+     * with any new animations. For example, if an item is currently animating from
+     * location A to B and another change dictates that it be animated to C, then the current
+     * A-B animation will be canceled and a new animation to C will be started.
+     */
+    private static class ItemAnimationInfo {
+        int id;
+        MenuItemLayoutInfo menuItemLayoutInfo;
+        Animator animator;
+        int animType;
+        static final int MOVE = 0;
+        static final int FADE_IN = 1;
+        static final int FADE_OUT = 2;
+
+        ItemAnimationInfo(int id, MenuItemLayoutInfo info, Animator anim, int animType) {
+            this.id = id;
+            menuItemLayoutInfo = info;
+            animator = anim;
+            this.animType = animType;
+        }
+    }
+
 }
diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java
index e2f8efc..ec2528f 100644
--- a/core/java/android/widget/DayPickerView.java
+++ b/core/java/android/widget/DayPickerView.java
@@ -187,7 +187,6 @@
      * @param setSelected whether to set the specified day as selected
      */
     private void setDate(long timeInMillis, boolean animate, boolean setSelected) {
-        // Set the selected day
         if (setSelected) {
             mSelectedDay.setTimeInMillis(timeInMillis);
         }
@@ -196,6 +195,9 @@
         if (position != getCurrentItem()) {
             setCurrentItem(position, animate);
         }
+
+        mTempCalendar.setTimeInMillis(timeInMillis);
+        mAdapter.setSelectedDay(mTempCalendar);
     }
 
     public long getDate() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 32b99a8..491826a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -557,7 +557,7 @@
         }
     }
 
-    private void hideInsertionPointCursorController() {
+    void hideInsertionPointCursorController() {
         if (mInsertionPointCursorController != null) {
             mInsertionPointCursorController.hide();
         }
@@ -1668,10 +1668,12 @@
         if (mSelectionActionMode != null) {
             // Selection action mode is already started
             // TODO: revisit invocations to minimize this case.
+            mSelectionActionMode.invalidate();
             return false;
         }
         ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
-        mSelectionActionMode = mTextView.startActionMode(actionModeCallback);
+        mSelectionActionMode = mTextView.startActionMode(
+                actionModeCallback, ActionMode.TYPE_FLOATING);
         return mSelectionActionMode != null;
     }
 
@@ -1681,6 +1683,7 @@
     boolean startSelectionActionModeWithSelection() {
         if (mSelectionActionMode != null) {
             // Selection action mode is already started
+            mSelectionActionMode.invalidate();
             return false;
         }
 
@@ -1704,7 +1707,8 @@
         // immediately hide the newly created action bar and would be visually distracting.
         if (!willExtract) {
             ActionMode.Callback actionModeCallback = new SelectionActionModeCallback();
-            mSelectionActionMode = mTextView.startActionMode(actionModeCallback);
+            mSelectionActionMode = mTextView.startActionMode(
+                    actionModeCallback, ActionMode.TYPE_FLOATING);
         }
 
         final boolean selectionStarted = mSelectionActionMode != null || willExtract;
@@ -2963,6 +2967,28 @@
 
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            mode.setTitle(mTextView.getContext().getString(
+                    com.android.internal.R.string.textSelectionCABTitle));
+            mode.setSubtitle(null);
+            mode.setTitleOptionalHint(true);
+            populateMenuWithItems(menu);
+
+            if (mCustomSelectionActionModeCallback != null) {
+                if (!mCustomSelectionActionModeCallback.onCreateActionMode(mode, menu)) {
+                    // The custom mode can choose to cancel the action mode
+                    return false;
+                }
+            }
+
+            if (menu.hasVisibleItems() || mode.getCustomView() != null) {
+                mTextView.setHasTransientState(true);
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        private void populateMenuWithItems(Menu menu) {
             final boolean legacy = mTextView.getContext().getApplicationInfo().targetSdkVersion <
                     Build.VERSION_CODES.LOLLIPOP;
             final Context context = !legacy && menu instanceof MenuBuilder ?
@@ -2971,11 +2997,6 @@
             final TypedArray styledAttributes = context.obtainStyledAttributes(
                     com.android.internal.R.styleable.SelectionModeDrawables);
 
-            mode.setTitle(mTextView.getContext().getString(
-                    com.android.internal.R.string.textSelectionCABTitle));
-            mode.setSubtitle(null);
-            mode.setTitleOptionalHint(true);
-
             if (mTextView.canCut()) {
                 menu.add(0, TextView.ID_CUT, 0, com.android.internal.R.string.cut).
                     setIcon(styledAttributes.getResourceId(
@@ -3010,37 +3031,33 @@
                     setShowAsAction(
                             MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
 
-            if (mTextView.isSuggestionsEnabled() && isCursorInsideSuggestionSpan()) {
-                menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace).
-                        setShowAsAction(
-                                MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
-            }
+            updateReplaceItem(menu);
 
             styledAttributes.recycle();
-
-            if (mCustomSelectionActionModeCallback != null) {
-                if (!mCustomSelectionActionModeCallback.onCreateActionMode(mode, menu)) {
-                    // The custom mode can choose to cancel the action mode
-                    return false;
-                }
-            }
-
-            if (menu.hasVisibleItems() || mode.getCustomView() != null) {
-                mTextView.setHasTransientState(true);
-                return true;
-            } else {
-                return false;
-            }
         }
 
         @Override
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            updateReplaceItem(menu);
+
             if (mCustomSelectionActionModeCallback != null) {
                 return mCustomSelectionActionModeCallback.onPrepareActionMode(mode, menu);
             }
             return true;
         }
 
+        private void updateReplaceItem(Menu menu) {
+            boolean canReplace = mTextView.isSuggestionsEnabled() && isCursorInsideSuggestionSpan();
+            boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null;
+            if (canReplace && !replaceItemExists) {
+                menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace).
+                setShowAsAction(
+                        MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+            } else if (!canReplace && replaceItemExists) {
+                menu.removeItem(TextView.ID_REPLACE);
+            }
+        }
+
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
             if (mCustomSelectionActionModeCallback != null &&
@@ -3091,6 +3108,17 @@
                         mTextView.getSelectionStart(), mTextView.getSelectionEnd(), mSelectionPath);
                 mSelectionPath.computeBounds(mSelectionBounds, true);
                 mSelectionBounds.bottom += mSelectionHandleHeight;
+            } else if (mCursorCount == 2) {
+                // We have a split cursor. In this case, we take the rectangle that includes both
+                // parts of the cursor to ensure we don't obscure either of them.
+                Rect firstCursorBounds = mCursorDrawable[0].getBounds();
+                Rect secondCursorBounds = mCursorDrawable[1].getBounds();
+                mSelectionBounds.set(
+                        Math.min(firstCursorBounds.left, secondCursorBounds.left),
+                        Math.min(firstCursorBounds.top, secondCursorBounds.top),
+                        Math.max(firstCursorBounds.right, secondCursorBounds.right),
+                        Math.max(firstCursorBounds.bottom, secondCursorBounds.bottom)
+                            + mInsertionHandleHeight);
             } else {
                 // We have a single cursor.
                 int line = mTextView.getLayout().getLineForOffset(mTextView.getSelectionStart());
@@ -3796,6 +3824,9 @@
             Selection.setSelection((Spannable) mTextView.getText(), offset,
                     mTextView.getSelectionEnd());
             updateDrawable();
+            if (mSelectionActionMode != null) {
+                mSelectionActionMode.invalidate();
+            }
         }
 
         @Override
@@ -3898,6 +3929,9 @@
         public void updateSelection(int offset) {
             Selection.setSelection((Spannable) mTextView.getText(),
                     mTextView.getSelectionStart(), offset);
+            if (mSelectionActionMode != null) {
+                mSelectionActionMode.invalidate();
+            }
             updateDrawable();
         }
 
diff --git a/core/java/android/widget/FastScroller.java b/core/java/android/widget/FastScroller.java
index 21213ac..4b5407a 100644
--- a/core/java/android/widget/FastScroller.java
+++ b/core/java/android/widget/FastScroller.java
@@ -46,6 +46,8 @@
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.ImageView.ScaleType;
 
+import com.android.internal.R;
+
 /**
  * Helper class for AbsListView to draw and control the Fast Scroll thumb
  */
@@ -82,6 +84,10 @@
     private static final int OVERLAY_AT_THUMB = 1;
     private static final int OVERLAY_ABOVE_THUMB = 2;
 
+    // Positions for thumb in relation to track.
+    private static final int THUMB_POSITION_MIDPOINT = 0;
+    private static final int THUMB_POSITION_INSIDE = 1;
+
     // Indices for mPreviewResId.
     private static final int PREVIEW_LEFT = 0;
     private static final int PREVIEW_RIGHT = 1;
@@ -100,7 +106,6 @@
     private final ImageView mThumbImage;
     private final ImageView mTrackImage;
     private final View mPreviewImage;
-
     /**
      * Preview image resource IDs for left- and right-aligned layouts. See
      * {@link #PREVIEW_LEFT} and {@link #PREVIEW_RIGHT}.
@@ -130,6 +135,11 @@
     private Drawable mThumbDrawable;
     private Drawable mTrackDrawable;
     private int mTextAppearance;
+    private int mThumbPosition;
+
+    // Used to convert between y-coordinate and thumb position within track.
+    private float mThumbOffset;
+    private float mThumbRange;
 
     /** Total width of decorations. */
     private int mWidth;
@@ -278,7 +288,6 @@
     }
 
     private void updateAppearance() {
-        final Context context = mList.getContext();
         int width = 0;
 
         // Add track to overlay if it has an image.
@@ -298,12 +307,9 @@
         // Account for minimum thumb width.
         mWidth = Math.max(width, mThumbMinWidth);
 
-        mPreviewImage.setMinimumWidth(mPreviewMinWidth);
-        mPreviewImage.setMinimumHeight(mPreviewMinHeight);
-
         if (mTextAppearance != 0) {
-            mPrimaryText.setTextAppearance(context, mTextAppearance);
-            mSecondaryText.setTextAppearance(context, mTextAppearance);
+            mPrimaryText.setTextAppearance(mTextAppearance);
+            mSecondaryText.setTextAppearance(mTextAppearance);
         }
 
         if (mTextColor != null) {
@@ -316,13 +322,11 @@
             mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
         }
 
-        final int textMinSize = Math.max(0, mPreviewMinHeight);
-        mPrimaryText.setMinimumWidth(textMinSize);
-        mPrimaryText.setMinimumHeight(textMinSize);
+        final int padding = mPreviewPadding;
         mPrimaryText.setIncludeFontPadding(false);
-        mSecondaryText.setMinimumWidth(textMinSize);
-        mSecondaryText.setMinimumHeight(textMinSize);
+        mPrimaryText.setPadding(padding, padding, padding, padding);
         mSecondaryText.setIncludeFontPadding(false);
+        mSecondaryText.setPadding(padding, padding, padding, padding);
 
         refreshDrawablePressedState();
     }
@@ -330,50 +334,53 @@
     public void setStyle(@StyleRes int resId) {
         final Context context = mList.getContext();
         final TypedArray ta = context.obtainStyledAttributes(null,
-                com.android.internal.R.styleable.FastScroll, android.R.attr.fastScrollStyle, resId);
+                R.styleable.FastScroll, R.attr.fastScrollStyle, resId);
         final int N = ta.getIndexCount();
         for (int i = 0; i < N; i++) {
             final int index = ta.getIndex(i);
             switch (index) {
-                case com.android.internal.R.styleable.FastScroll_position:
+                case R.styleable.FastScroll_position:
                     mOverlayPosition = ta.getInt(index, OVERLAY_FLOATING);
                     break;
-                case com.android.internal.R.styleable.FastScroll_backgroundLeft:
+                case R.styleable.FastScroll_backgroundLeft:
                     mPreviewResId[PREVIEW_LEFT] = ta.getResourceId(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_backgroundRight:
+                case R.styleable.FastScroll_backgroundRight:
                     mPreviewResId[PREVIEW_RIGHT] = ta.getResourceId(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_thumbDrawable:
+                case R.styleable.FastScroll_thumbDrawable:
                     mThumbDrawable = ta.getDrawable(index);
                     break;
-                case com.android.internal.R.styleable.FastScroll_trackDrawable:
+                case R.styleable.FastScroll_trackDrawable:
                     mTrackDrawable = ta.getDrawable(index);
                     break;
-                case com.android.internal.R.styleable.FastScroll_textAppearance:
+                case R.styleable.FastScroll_textAppearance:
                     mTextAppearance = ta.getResourceId(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_textColor:
+                case R.styleable.FastScroll_textColor:
                     mTextColor = ta.getColorStateList(index);
                     break;
-                case com.android.internal.R.styleable.FastScroll_textSize:
+                case R.styleable.FastScroll_textSize:
                     mTextSize = ta.getDimensionPixelSize(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_minWidth:
+                case R.styleable.FastScroll_minWidth:
                     mPreviewMinWidth = ta.getDimensionPixelSize(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_minHeight:
+                case R.styleable.FastScroll_minHeight:
                     mPreviewMinHeight = ta.getDimensionPixelSize(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_thumbMinWidth:
+                case R.styleable.FastScroll_thumbMinWidth:
                     mThumbMinWidth = ta.getDimensionPixelSize(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_thumbMinHeight:
+                case R.styleable.FastScroll_thumbMinHeight:
                     mThumbMinHeight = ta.getDimensionPixelSize(index, 0);
                     break;
-                case com.android.internal.R.styleable.FastScroll_padding:
+                case R.styleable.FastScroll_padding:
                     mPreviewPadding = ta.getDimensionPixelSize(index, 0);
                     break;
+                case R.styleable.FastScroll_thumbPosition:
+                    mThumbPosition = ta.getInt(index, THUMB_POSITION_MIDPOINT);
+                    break;
             }
         }
 
@@ -478,14 +485,16 @@
             final int previewResId = mPreviewResId[mLayoutFromRight ? PREVIEW_RIGHT : PREVIEW_LEFT];
             mPreviewImage.setBackgroundResource(previewResId);
 
-            // Add extra padding for text.
-            final Drawable background = mPreviewImage.getBackground();
-            if (background != null) {
-                final Rect padding = mTempBounds;
-                background.getPadding(padding);
-                padding.offset(mPreviewPadding, mPreviewPadding);
-                mPreviewImage.setPadding(padding.left, padding.top, padding.right, padding.bottom);
-            }
+            // Propagate padding to text min width/height.
+            final int textMinWidth = Math.max(0, mPreviewMinWidth - mPreviewImage.getPaddingLeft()
+                    - mPreviewImage.getPaddingRight());
+            mPrimaryText.setMinimumWidth(textMinWidth);
+            mSecondaryText.setMinimumWidth(textMinWidth);
+
+            final int textMinHeight = Math.max(0, mPreviewMinHeight - mPreviewImage.getPaddingTop()
+                    - mPreviewImage.getPaddingBottom());
+            mPrimaryText.setMinimumHeight(textMinHeight);
+            mSecondaryText.setMinimumHeight(textMinHeight);
 
             // Requires re-layout.
             updateLayout();
@@ -560,6 +569,8 @@
         layoutThumb();
         layoutTrack();
 
+        updateOffsetAndRange();
+
         final Rect bounds = mTempBounds;
         measurePreview(mPrimaryText, bounds);
         applyLayout(mPrimaryText, bounds);
@@ -758,15 +769,45 @@
         final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
         track.measure(widthMeasureSpec, heightMeasureSpec);
 
+        final int top;
+        final int bottom;
+        if (mThumbPosition == THUMB_POSITION_INSIDE) {
+            top = container.top;
+            bottom = container.bottom;
+        } else {
+            final int thumbHalfHeight = thumb.getHeight() / 2;
+            top = container.top + thumbHalfHeight;
+            bottom = container.bottom - thumbHalfHeight;
+        }
+
         final int trackWidth = track.getMeasuredWidth();
-        final int thumbHalfHeight = thumb.getHeight() / 2;
         final int left = thumb.getLeft() + (thumb.getWidth() - trackWidth) / 2;
         final int right = left + trackWidth;
-        final int top = container.top + thumbHalfHeight;
-        final int bottom = container.bottom - thumbHalfHeight;
         track.layout(left, top, right, bottom);
     }
 
+    /**
+     * Updates the offset and range used to convert from absolute y-position to
+     * thumb position within the track.
+     */
+    private void updateOffsetAndRange() {
+        final View trackImage = mTrackImage;
+        final View thumbImage = mThumbImage;
+        final float min;
+        final float max;
+        if (mThumbPosition == THUMB_POSITION_INSIDE) {
+            final float halfThumbHeight = thumbImage.getHeight() / 2f;
+            min = trackImage.getTop() + halfThumbHeight;
+            max = trackImage.getBottom() - halfThumbHeight;
+        } else{
+            min = trackImage.getTop();
+            max = trackImage.getBottom();
+        }
+
+        mThumbOffset = min;
+        mThumbRange = max - min;
+    }
+
     private void setState(int state) {
         mList.removeCallbacks(mDeferHide);
 
@@ -1145,18 +1186,8 @@
      *            to place the thumb.
      */
     private void setThumbPos(float position) {
-        final Rect container = mContainerRect;
-        final int top = container.top;
-        final int bottom = container.bottom;
-
-        final View trackImage = mTrackImage;
-        final View thumbImage = mThumbImage;
-        final float min = trackImage.getTop();
-        final float max = trackImage.getBottom();
-        final float offset = min;
-        final float range = max - min;
-        final float thumbMiddle = position * range + offset;
-        thumbImage.setTranslationY(thumbMiddle - thumbImage.getHeight() / 2);
+        final float thumbMiddle = position * mThumbRange + mThumbOffset;
+        mThumbImage.setTranslationY(thumbMiddle - mThumbImage.getHeight() / 2f);
 
         final View previewImage = mPreviewImage;
         final float previewHalfHeight = previewImage.getHeight() / 2f;
@@ -1175,6 +1206,9 @@
         }
 
         // Center the preview on the thumb, constrained to the list bounds.
+        final Rect container = mContainerRect;
+        final int top = container.top;
+        final int bottom = container.bottom;
         final float minP = top + previewHalfHeight;
         final float maxP = bottom - previewHalfHeight;
         final float previewMiddle = MathUtils.constrain(previewPos, minP, maxP);
@@ -1186,19 +1220,13 @@
     }
 
     private float getPosFromMotionEvent(float y) {
-        final View trackImage = mTrackImage;
-        final float min = trackImage.getTop();
-        final float max = trackImage.getBottom();
-        final float offset = min;
-        final float range = max - min;
-
         // If the list is the same height as the thumbnail or shorter,
         // effectively disable scrolling.
-        if (range <= 0) {
+        if (mThumbRange <= 0) {
             return 0f;
         }
 
-        return MathUtils.constrain((y - offset) / range, 0f, 1f);
+        return MathUtils.constrain((y - mThumbOffset) / mThumbRange, 0f, 1f);
     }
 
     /**
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index c6e3dc8..be0ca71 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
+import android.os.Bundle;
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.MathUtils;
@@ -32,12 +33,15 @@
 import android.view.ViewGroup;
 import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
 import android.view.animation.GridLayoutAnimationController;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -117,7 +121,7 @@
     }
 
     public GridView(Context context, AttributeSet attrs) {
-        this(context, attrs, com.android.internal.R.attr.gridViewStyle);
+        this(context, attrs, R.attr.gridViewStyle);
     }
 
     public GridView(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -128,30 +132,30 @@
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.GridView, defStyleAttr, defStyleRes);
+                attrs, R.styleable.GridView, defStyleAttr, defStyleRes);
 
         int hSpacing = a.getDimensionPixelOffset(
-                com.android.internal.R.styleable.GridView_horizontalSpacing, 0);
+                R.styleable.GridView_horizontalSpacing, 0);
         setHorizontalSpacing(hSpacing);
 
         int vSpacing = a.getDimensionPixelOffset(
-                com.android.internal.R.styleable.GridView_verticalSpacing, 0);
+                R.styleable.GridView_verticalSpacing, 0);
         setVerticalSpacing(vSpacing);
 
-        int index = a.getInt(com.android.internal.R.styleable.GridView_stretchMode, STRETCH_COLUMN_WIDTH);
+        int index = a.getInt(R.styleable.GridView_stretchMode, STRETCH_COLUMN_WIDTH);
         if (index >= 0) {
             setStretchMode(index);
         }
 
-        int columnWidth = a.getDimensionPixelOffset(com.android.internal.R.styleable.GridView_columnWidth, -1);
+        int columnWidth = a.getDimensionPixelOffset(R.styleable.GridView_columnWidth, -1);
         if (columnWidth > 0) {
             setColumnWidth(columnWidth);
         }
 
-        int numColumns = a.getInt(com.android.internal.R.styleable.GridView_numColumns, 1);
+        int numColumns = a.getInt(R.styleable.GridView_numColumns, 1);
         setNumColumns(numColumns);
 
-        index = a.getInt(com.android.internal.R.styleable.GridView_gravity, -1);
+        index = a.getInt(R.styleable.GridView_gravity, -1);
         if (index >= 0) {
             setGravity(index);
         }
@@ -2356,6 +2360,36 @@
         final CollectionInfo collectionInfo = CollectionInfo.obtain(
                 rowsCount, columnsCount, false, selectionMode);
         info.setCollectionInfo(collectionInfo);
+
+        if (columnsCount > 0 || rowsCount > 0) {
+            info.addAction(AccessibilityAction.ACTION_SCROLL_TO_POSITION);
+        }
+    }
+
+    /** @hide */
+    @Override
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
+            return true;
+        }
+
+        switch (action) {
+            case R.id.accessibilityActionScrollToPosition: {
+                // GridView only supports scrolling in one direction, so we can
+                // ignore the column argument.
+                final int numColumns = getNumColumns();
+                final int row = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_ROW_INT, -1);
+                final int position = Math.min(row * numColumns, getCount() - 1);
+                if (row >= 0) {
+                    // The accessibility service gets data asynchronously, so
+                    // we'll be a little lenient by clamping the last position.
+                    smoothScrollToPosition(position);
+                    return true;
+                }
+            } break;
+        }
+
+        return false;
     }
 
     @Override
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 041796b..6d2f368 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -687,12 +687,19 @@
         return mDrawMatrix;
     }
 
+    /**
+     * Adds a transformation {@link Matrix} that is applied
+     * to the view's drawable when it is drawn.  Allows custom scaling,
+     * translation, and perspective distortion.
+     * 
+     * @param matrix the transformation parameters in matrix form
+     */
     public void setImageMatrix(Matrix matrix) {
-        // collaps null and identity to just null
+        // collapse null and identity to just null
         if (matrix != null && matrix.isIdentity()) {
             matrix = null;
         }
-        
+
         // don't invalidate unless we're actually changing our matrix
         if (matrix == null && !mMatrix.isIdentity() ||
                 matrix != null && !mMatrix.equals(matrix)) {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index ee2c055..def5929 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.os.Bundle;
 import android.os.Trace;
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
@@ -42,6 +43,7 @@
 import android.view.ViewParent;
 import android.view.ViewRootImpl;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo;
 import android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
@@ -3893,6 +3895,33 @@
         final CollectionInfo collectionInfo = CollectionInfo.obtain(
                 rowsCount, 1, false, selectionMode);
         info.setCollectionInfo(collectionInfo);
+
+        if (rowsCount > 0) {
+            info.addAction(AccessibilityAction.ACTION_SCROLL_TO_POSITION);
+        }
+    }
+
+    /** @hide */
+    @Override
+    public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+        if (super.performAccessibilityActionInternal(action, arguments)) {
+            return true;
+        }
+
+        switch (action) {
+            case R.id.accessibilityActionScrollToPosition: {
+                final int row = arguments.getInt(AccessibilityNodeInfo.ACTION_ARGUMENT_ROW_INT, -1);
+                final int position = Math.min(row, getCount() - 1);
+                if (row >= 0) {
+                    // The accessibility service gets data asynchronously, so
+                    // we'll be a little lenient by clamping the last position.
+                    smoothScrollToPosition(position);
+                    return true;
+                }
+            } break;
+        }
+
+        return false;
     }
 
     @Override
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 50d701a..24e9cbe 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -60,7 +60,6 @@
 
 import java.util.ArrayList;
 
-
 /**
  * <p>
  * Visual indicator of progress in some operation.  Displays a bar to the user
@@ -266,9 +265,14 @@
 
         final Drawable progressDrawable = a.getDrawable(R.styleable.ProgressBar_progressDrawable);
         if (progressDrawable != null) {
-            // Calling this method can set mMaxHeight, make sure the corresponding
-            // XML attribute for mMaxHeight is read after calling this method
-            setProgressDrawableTiled(progressDrawable);
+            // Calling setProgressDrawable can set mMaxHeight, so make sure the
+            // corresponding XML attribute for mMaxHeight is read after calling
+            // this method.
+            if (needsTileify(progressDrawable)) {
+                setProgressDrawableTiled(progressDrawable);
+            } else {
+                setProgressDrawable(progressDrawable);
+            }
         }
 
 
@@ -292,13 +296,17 @@
 
         setProgress(a.getInt(R.styleable.ProgressBar_progress, mProgress));
 
-        setSecondaryProgress(
-                a.getInt(R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
+        setSecondaryProgress(a.getInt(
+                R.styleable.ProgressBar_secondaryProgress, mSecondaryProgress));
 
         final Drawable indeterminateDrawable = a.getDrawable(
                 R.styleable.ProgressBar_indeterminateDrawable);
         if (indeterminateDrawable != null) {
-            setIndeterminateDrawableTiled(indeterminateDrawable);
+            if (needsTileify(indeterminateDrawable)) {
+                setIndeterminateDrawableTiled(indeterminateDrawable);
+            } else {
+                setIndeterminateDrawable(indeterminateDrawable);
+            }
         }
 
         mOnlyIndeterminate = a.getBoolean(
@@ -316,7 +324,7 @@
                 mProgressTintInfo = new ProgressTintInfo();
             }
             mProgressTintInfo.mProgressTintMode = Drawable.parseTintMode(a.getInt(
-                    R.styleable.ProgressBar_progressBackgroundTintMode, -1), null);
+                    R.styleable.ProgressBar_progressTintMode, -1), null);
             mProgressTintInfo.mHasProgressTintMode = true;
         }
 
@@ -334,7 +342,7 @@
                 mProgressTintInfo = new ProgressTintInfo();
             }
             mProgressTintInfo.mProgressBackgroundTintMode = Drawable.parseTintMode(a.getInt(
-                    R.styleable.ProgressBar_progressTintMode, -1), null);
+                    R.styleable.ProgressBar_progressBackgroundTintMode, -1), null);
             mProgressTintInfo.mHasProgressBackgroundTintMode = true;
         }
 
@@ -365,7 +373,7 @@
             mProgressTintInfo.mHasSecondaryProgressTint = true;
         }
 
-        if (a.hasValue(R.styleable.ProgressBar_indeterminateTint)) {
+        if (a.hasValue(R.styleable.ProgressBar_indeterminateTintMode)) {
             if (mProgressTintInfo == null) {
                 mProgressTintInfo = new ProgressTintInfo();
             }
@@ -395,6 +403,45 @@
     }
 
     /**
+     * Returns {@code true} if the target drawable needs to be tileified.
+     *
+     * @param dr the drawable to check
+     * @return {@code true} if the target drawable needs to be tileified,
+     *         {@code false} otherwise
+     */
+    private static boolean needsTileify(Drawable dr) {
+        if (dr instanceof LayerDrawable) {
+            final LayerDrawable orig = (LayerDrawable) dr;
+            final int N = orig.getNumberOfLayers();
+            for (int i = 0; i < N; i++) {
+                if (needsTileify(orig.getDrawable(i))) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        if (dr instanceof StateListDrawable) {
+            final StateListDrawable in = (StateListDrawable) dr;
+            final int N = in.getStateCount();
+            for (int i = 0; i < N; i++) {
+                if (needsTileify(in.getStateDrawable(i))) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        // If there's a bitmap that's not wrapped with a ClipDrawable or
+        // ScaleDrawable, we'll need to wrap it and apply tiling.
+        if (dr instanceof BitmapDrawable) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
      * Converts a drawable to a tiled version of itself. It will recursively
      * traverse layer and state list drawables.
      */
@@ -448,18 +495,14 @@
                 mSampleTile = tileBitmap;
             }
 
-            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
-            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
-                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
-            shapeDrawable.getPaint().setShader(bitmapShader);
+            final BitmapDrawable clone = (BitmapDrawable) bitmap.getConstantState().newDrawable();
+            clone.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
 
-            // Ensure the tint and filter are propagated in the correct order.
-            shapeDrawable.setTintList(bitmap.getTint());
-            shapeDrawable.setTintMode(bitmap.getTintMode());
-            shapeDrawable.setColorFilter(bitmap.getColorFilter());
-
-            return clip ? new ClipDrawable(
-                    shapeDrawable, Gravity.LEFT, ClipDrawable.HORIZONTAL) : shapeDrawable;
+            if (clip) {
+                return new ClipDrawable(clone, Gravity.LEFT, ClipDrawable.HORIZONTAL);
+            } else {
+                return clone;
+            }
         }
 
         return drawable;
@@ -1810,9 +1853,7 @@
         }
         if (mRefreshProgressRunnable != null) {
             removeCallbacks(mRefreshProgressRunnable);
-        }
-        if (mRefreshProgressRunnable != null && mRefreshIsPosted) {
-            removeCallbacks(mRefreshProgressRunnable);
+            mRefreshIsPosted = false;
         }
         if (mAccessibilityEventSender != null) {
             removeCallbacks(mAccessibilityEventSender);
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 143dea4..9571109 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -79,8 +79,10 @@
     // Transparent alpha level
     private static final int ALPHA_TRANSPARENT = 0;
 
-    private static final int DEGREES_FOR_ONE_HOUR = 30;
-    private static final int DEGREES_FOR_ONE_MINUTE = 6;
+    private static final int HOURS_IN_CIRCLE = 12;
+    private static final int MINUTES_IN_CIRCLE = 60;
+    private static final int DEGREES_FOR_ONE_HOUR = 360 / HOURS_IN_CIRCLE;
+    private static final int DEGREES_FOR_ONE_MINUTE = 360 / MINUTES_IN_CIRCLE;
 
     private static final int[] HOURS_NUMBERS = {12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
     private static final int[] HOURS_NUMBERS_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
@@ -140,8 +142,7 @@
     private final float[] mInnerTextX = new float[12];
     private final float[] mInnerTextY = new float[12];
 
-    private final int[] mLineLength = new int[3];
-    private final int[] mSelectionDegrees = new int[3];
+    private final int[] mSelectionDegrees = new int[2];
 
     private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<>();
     private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<>();
@@ -168,13 +169,13 @@
     private int mYCenter;
     private int mCircleRadius;
 
-    private int mMinHypotenuseForInnerNumber;
-    private int mMaxHypotenuseForOuterNumber;
-    private int mHalfwayHypotenusePoint;
+    private int mMinDistForInnerNumber;
+    private int mMaxDistForOuterNumber;
+    private int mHalfwayDist;
 
     private String[] mOuterTextHours;
     private String[] mInnerTextHours;
-    private String[] mOuterTextMinutes;
+    private String[] mMinutesText;
     private AnimatorSet mTransition;
 
     private int mAmOrPm;
@@ -462,11 +463,10 @@
     private void setCurrentHourInternal(int hour, boolean callback, boolean autoAdvance) {
         final int degrees = (hour % 12) * DEGREES_FOR_ONE_HOUR;
         mSelectionDegrees[HOURS] = degrees;
-        mSelectionDegrees[HOURS_INNER] = degrees;
 
         // 0 is 12 AM (midnight) and 12 is 12 PM (noon).
         final int amOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM;
-        final boolean isOnInnerCircle = mIs24HourMode && hour >= 1 && hour <= 12;
+        final boolean isOnInnerCircle = getInnerCircleForHour(hour);
         if (mAmOrPm != amOrPm || mIsOnInnerCircle != isOnInnerCircle) {
             mAmOrPm = amOrPm;
             mIsOnInnerCircle = isOnInnerCircle;
@@ -488,8 +488,7 @@
      * @return the current hour between 0 and 23 (inclusive)
      */
     public int getCurrentHour() {
-        return getHourForDegrees(
-                mSelectionDegrees[mIsOnInnerCircle ? HOURS_INNER : HOURS], mIsOnInnerCircle);
+        return getHourForDegrees(mSelectionDegrees[HOURS], mIsOnInnerCircle);
     }
 
     private int getHourForDegrees(int degrees, boolean innerCircle) {
@@ -497,11 +496,11 @@
         if (mIs24HourMode) {
             // Convert the 12-hour value into 24-hour time based on where the
             // selector is positioned.
-            if (innerCircle && hour == 0) {
-                // Inner circle is 1 through 12.
+            if (!innerCircle && hour == 0) {
+                // Outer circle is 1 through 12.
                 hour = 12;
-            } else if (!innerCircle && hour != 0) {
-                // Outer circle is 13 through 23 and 0.
+            } else if (innerCircle && hour != 0) {
+                // Inner circle is 13 through 23 and 0.
                 hour += 12;
             }
         } else if (mAmOrPm == PM) {
@@ -510,6 +509,9 @@
         return hour;
     }
 
+    /**
+     * @param hour the hour in 24-hour time or 12-hour time
+     */
     private int getDegreesForHour(int hour) {
         // Convert to be 0-11.
         if (mIs24HourMode) {
@@ -522,12 +524,19 @@
         return hour * DEGREES_FOR_ONE_HOUR;
     }
 
+    /**
+     * @param hour the hour in 24-hour time or 12-hour time
+     */
+    private boolean getInnerCircleForHour(int hour) {
+        return mIs24HourMode && (hour == 0 || hour > 12);
+    }
+
     public void setCurrentMinute(int minute) {
         setCurrentMinuteInternal(minute, true);
     }
 
     private void setCurrentMinuteInternal(int minute, boolean callback) {
-        mSelectionDegrees[MINUTES] = (minute % 60) * DEGREES_FOR_ONE_MINUTE;
+        mSelectionDegrees[MINUTES] = (minute % MINUTES_IN_CIRCLE) * DEGREES_FOR_ONE_MINUTE;
 
         invalidate();
 
@@ -572,6 +581,7 @@
 
         initData();
         invalidate();
+        mTouchHelper.invalidateRoot();
     }
 
     public void showMinutes(boolean animate) {
@@ -587,6 +597,7 @@
 
         initData();
         invalidate();
+        mTouchHelper.invalidateRoot();
     }
 
     private void initHoursAndMinutesText() {
@@ -608,7 +619,7 @@
             mInnerTextHours = mHours12Texts;
         }
 
-        mOuterTextMinutes = mMinutesTexts;
+        mMinutesText = mMinutesTexts;
 
         final int hoursAlpha = mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT;
         mAlpha[HOURS].setValue(hoursAlpha);
@@ -627,9 +638,9 @@
         mYCenter = getHeight() / 2;
         mCircleRadius = Math.min(mXCenter, mYCenter);
 
-        mMinHypotenuseForInnerNumber = mCircleRadius - mTextInset[HOURS_INNER] - mSelectorRadius;
-        mMaxHypotenuseForOuterNumber = mCircleRadius - mTextInset[HOURS] + mSelectorRadius;
-        mHalfwayHypotenusePoint = mCircleRadius - (mTextInset[HOURS] + mTextInset[HOURS_INNER]) / 2;
+        mMinDistForInnerNumber = mCircleRadius - mTextInset[HOURS_INNER] - mSelectorRadius;
+        mMaxDistForOuterNumber = mCircleRadius - mTextInset[HOURS] + mSelectorRadius;
+        mHalfwayDist = mCircleRadius - (mTextInset[HOURS] + mTextInset[HOURS_INNER]) / 2;
 
         calculatePositionsHours();
         calculatePositionsMinutes();
@@ -674,6 +685,7 @@
     private void drawMinutes(Canvas canvas, float alphaMod) {
         final int minutesAlpha = (int) (mAlpha[MINUTES].getValue() * alphaMod + 0.5f);
         if (minutesAlpha > 0) {
+            // Draw the minute selector under the elements.
             drawSelector(canvas, MINUTES, mSelectorPath, alphaMod);
 
             // Exclude the selector region, then draw minutes with no
@@ -681,7 +693,7 @@
             canvas.save(Canvas.CLIP_SAVE_FLAG);
             canvas.clipPath(mSelectorPath, Region.Op.DIFFERENCE);
             drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
-                    mOuterTextMinutes, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
+                    mMinutesText, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
                     minutesAlpha, false, 0, false);
             canvas.restore();
 
@@ -690,7 +702,7 @@
             canvas.save(Canvas.CLIP_SAVE_FLAG);
             canvas.clipPath(mSelectorPath, Region.Op.INTERSECT);
             drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
-                    mOuterTextMinutes, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
+                    mMinutesText, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
                     minutesAlpha, true, mSelectionDegrees[MINUTES], true);
             canvas.restore();
         }
@@ -718,7 +730,7 @@
         // Calculate the current radius at which to place the selection circle.
         final int selRadius = mSelectorRadius;
         final int selLength = mCircleRadius - mTextInset[index];
-        final double selAngleRad = Math.toRadians(mSelectionDegrees[index]);
+        final double selAngleRad = Math.toRadians(mSelectionDegrees[index % 2]);
         final float selCenterX = mXCenter + selLength * (float) Math.sin(selAngleRad);
         final float selCenterY = mYCenter - selLength * (float) Math.cos(selAngleRad);
 
@@ -734,10 +746,10 @@
         }
 
         // Draw the dot if we're between two items.
-        final boolean shouldDrawDot = mSelectionDegrees[index] % 30 != 0;
+        final boolean shouldDrawDot = mSelectionDegrees[index % 2] % 30 != 0;
         if (shouldDrawDot) {
             final Paint dotPaint = mPaintSelector[index % 2][SELECTOR_DOT];
-            dotPaint.setColor(color);
+            dotPaint.setColor(mSelectorDotColor);
             canvas.drawCircle(selCenterX, selCenterY, mSelectorDotRadius, dotPaint);
         }
 
@@ -898,56 +910,43 @@
     }
 
     private int getDegreesFromXY(float x, float y, boolean constrainOutside) {
-        final double hypotenuse = Math.sqrt(
-                (y - mYCenter) * (y - mYCenter) + (x - mXCenter) * (x - mXCenter));
+        // Ensure the point is inside the touchable area.
+        final int innerBound;
+        final int outerBound;
+        if (mIs24HourMode && mShowHours) {
+            innerBound = mMinDistForInnerNumber;
+            outerBound = mMaxDistForOuterNumber;
+        } else {
+            final int index = mShowHours ? HOURS : MINUTES;
+            final int center = mCircleRadius - mTextInset[index];
+            innerBound = center - mSelectorRadius;
+            outerBound = center + mSelectorRadius;
+        }
 
-        // Basic check if we're outside the range of the disk
-        if (constrainOutside && hypotenuse > mCircleRadius) {
+        final double dX = x - mXCenter;
+        final double dY = y - mYCenter;
+        final double distFromCenter = Math.sqrt(dX * dX + dY * dY);
+        if (distFromCenter < innerBound || constrainOutside && distFromCenter > outerBound) {
             return -1;
         }
 
-        // Check
+        // Convert to degrees.
+        final int degrees = (int) (Math.toDegrees(Math.atan2(dY, dX) + Math.PI / 2) + 0.5);
+        if (degrees < 0) {
+            return degrees + 360;
+        } else {
+            return degrees;
+        }
+    }
+
+    private boolean getInnerCircleFromXY(float x, float y) {
         if (mIs24HourMode && mShowHours) {
-            if (hypotenuse >= mMinHypotenuseForInnerNumber
-                    && hypotenuse <= mHalfwayHypotenusePoint) {
-                mIsOnInnerCircle = true;
-            } else if ((hypotenuse <= mMaxHypotenuseForOuterNumber || !constrainOutside)
-                    && hypotenuse >= mHalfwayHypotenusePoint) {
-                mIsOnInnerCircle = false;
-            } else {
-                return -1;
-            }
-        } else {
-            final int index =  (mShowHours) ? HOURS : MINUTES;
-            final float length = (mCircleRadius - mTextInset[index]);
-            final int distanceToNumber = (int) (hypotenuse - length);
-            final int maxAllowedDistance = mTextInset[index];
-            if (distanceToNumber < -maxAllowedDistance
-                    || (constrainOutside && distanceToNumber > maxAllowedDistance)) {
-                return -1;
-            }
+            final double dX = x - mXCenter;
+            final double dY = y - mYCenter;
+            final double distFromCenter = Math.sqrt(dX * dX + dY * dY);
+            return distFromCenter <= mHalfwayDist;
         }
-
-        final float opposite = Math.abs(y - mYCenter);
-        int degrees = (int) (Math.toDegrees(Math.asin(opposite / hypotenuse)) + 0.5);
-
-        // Now we have to translate to the correct quadrant.
-        final boolean rightSide = (x > mXCenter);
-        final boolean topSide = (y < mYCenter);
-        if (rightSide) {
-            if (topSide) {
-                degrees = 90 - degrees;
-            } else {
-                degrees = 90 + degrees;
-            }
-        } else {
-            if (topSide) {
-                degrees = 270 + degrees;
-            } else {
-                degrees = 270 - degrees;
-            }
-        }
-        return degrees;
+        return false;
     }
 
     boolean mChangedDuringTouch = false;
@@ -987,34 +986,28 @@
 
     private boolean handleTouchInput(
             float x, float y, boolean forceSelection, boolean autoAdvance) {
-        // Calling getDegreesFromXY has side effects, so cache
-        // whether we used to be on the inner circle.
-        final boolean wasOnInnerCircle = mIsOnInnerCircle;
+        final boolean isOnInnerCircle = getInnerCircleFromXY(x, y);
         final int degrees = getDegreesFromXY(x, y, false);
         if (degrees == -1) {
             return false;
         }
 
-        final int[] selectionDegrees = mSelectionDegrees;
         final int type;
         final int newValue;
         final boolean valueChanged;
 
         if (mShowHours) {
             final int snapDegrees = snapOnly30s(degrees, 0) % 360;
-            valueChanged = selectionDegrees[HOURS] != snapDegrees
-                    || selectionDegrees[HOURS_INNER] != snapDegrees
-                    || wasOnInnerCircle != mIsOnInnerCircle;
-
-            selectionDegrees[HOURS] = snapDegrees;
-            selectionDegrees[HOURS_INNER] = snapDegrees;
+            valueChanged = mIsOnInnerCircle != isOnInnerCircle
+                    || mSelectionDegrees[HOURS] != snapDegrees;
+            mIsOnInnerCircle = isOnInnerCircle;
+            mSelectionDegrees[HOURS] = snapDegrees;
             type = HOURS;
             newValue = getCurrentHour();
         } else {
             final int snapDegrees = snapPrefer30s(degrees) % 360;
-            valueChanged = selectionDegrees[MINUTES] != snapDegrees;
-
-            selectionDegrees[MINUTES] = snapDegrees;
+            valueChanged = mSelectionDegrees[MINUTES] != snapDegrees;
+            mSelectionDegrees[MINUTES] = snapDegrees;
             type = MINUTES;
             newValue = getCurrentMinute();
         }
@@ -1132,17 +1125,11 @@
         @Override
         protected int getVirtualViewAt(float x, float y) {
             final int id;
-
-            // Calling getDegreesXY() has side-effects, so we need to cache the
-            // current inner circle value and restore after the call.
-            final boolean wasOnInnerCircle = mIsOnInnerCircle;
             final int degrees = getDegreesFromXY(x, y, true);
-            final boolean isOnInnerCircle = mIsOnInnerCircle;
-            mIsOnInnerCircle = wasOnInnerCircle;
-
             if (degrees != -1) {
                 final int snapDegrees = snapOnly30s(degrees, 0) % 360;
                 if (mShowHours) {
+                    final boolean isOnInnerCircle = getInnerCircleFromXY(x, y);
                     final int hour24 = getHourForDegrees(snapDegrees, isOnInnerCircle);
                     final int hour = mIs24HourMode ? hour24 : hour24To12(hour24);
                     id = makeId(TYPE_HOUR, hour);
@@ -1153,8 +1140,10 @@
 
                     // If the touched minute is closer to the current minute
                     // than it is to the snapped minute, return current.
+                    final int currentOffset = getCircularDiff(current, touched, MINUTES_IN_CIRCLE);
+                    final int snappedOffset = getCircularDiff(snapped, touched, MINUTES_IN_CIRCLE);
                     final int minute;
-                    if (Math.abs(current - touched) < Math.abs(snapped - touched)) {
+                    if (currentOffset < snappedOffset) {
                         minute = current;
                     } else {
                         minute = snapped;
@@ -1168,6 +1157,20 @@
             return id;
         }
 
+        /**
+         * Returns the difference in degrees between two values along a circle.
+         *
+         * @param first value in the range [0,max]
+         * @param second value in the range [0,max]
+         * @param max the maximum value along the circle
+         * @return the difference in between the two values
+         */
+        private int getCircularDiff(int first, int second, int max) {
+            final int diff = Math.abs(first - second);
+            final int midpoint = max / 2;
+            return (diff > midpoint) ? (max - diff) : diff;
+        }
+
         @Override
         protected void getVisibleVirtualViews(IntArray virtualViewIds) {
             if (mShowHours) {
@@ -1178,7 +1181,7 @@
                 }
             } else {
                 final int current = getCurrentMinute();
-                for (int i = 0; i < 60; i += MINUTE_INCREMENT) {
+                for (int i = 0; i < MINUTES_IN_CIRCLE; i += MINUTE_INCREMENT) {
                     virtualViewIds.add(makeId(TYPE_MINUTE, i));
 
                     // If the current minute falls between two increments,
@@ -1236,7 +1239,7 @@
                 if (value < current && nextValue > current) {
                     // The current value is between two snap values.
                     return makeId(type, current);
-                } else if (nextValue < 60) {
+                } else if (nextValue < MINUTES_IN_CIRCLE) {
                     return makeId(type, nextValue);
                 }
             }
@@ -1290,7 +1293,7 @@
             final float centerRadius;
             final float degrees;
             if (type == TYPE_HOUR) {
-                final boolean innerCircle = mIs24HourMode && value > 0 && value <= 12;
+                final boolean innerCircle = getInnerCircleForHour(value);
                 if (innerCircle) {
                     centerRadius = mCircleRadius - mTextInset[HOURS_INNER];
                     radius = mSelectorRadius;
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 349f3f0..a50941b 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -815,12 +815,12 @@
         mContext = context;
         mIntent = intent;
 
-        mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
-
-        mLayoutInflater = LayoutInflater.from(context);
         if (mIntent == null) {
             throw new IllegalArgumentException("Non-null Intent must be specified.");
         }
+
+        mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1);
+        mLayoutInflater = LayoutInflater.from(context);
         mRequestedViews = new RemoteViewsFrameLayoutRefSet();
 
         // Strip the previously injected app widget id from service intent
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 3fb096c6..d9f1f0e 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -80,11 +80,12 @@
     private final SimpleDateFormat mTitleFormatter;
     private final SimpleDateFormat mDayOfWeekFormatter;
 
-    private final int mMonthHeight;
-    private final int mDayOfWeekHeight;
-    private final int mDayHeight;
-    private final int mCellWidth;
-    private final int mDaySelectorRadius;
+    // Desired dimensions.
+    private final int mDesiredMonthHeight;
+    private final int mDesiredDayOfWeekHeight;
+    private final int mDesiredDayHeight;
+    private final int mDesiredCellWidth;
+    private final int mDesiredDaySelectorRadius;
 
     // Next/previous drawables.
     private final Drawable mPrevDrawable;
@@ -99,6 +100,13 @@
     private int mMonth;
     private int mYear;
 
+    // Dimensions as laid out.
+    private int mMonthHeight;
+    private int mDayOfWeekHeight;
+    private int mDayHeight;
+    private int mCellWidth;
+    private int mDaySelectorRadius;
+
     private int mPaddedWidth;
     private int mPaddedHeight;
 
@@ -158,11 +166,11 @@
         super(context, attrs, defStyleAttr, defStyleRes);
 
         final Resources res = context.getResources();
-        mMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
-        mDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
-        mDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
-        mCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
-        mDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
+        mDesiredMonthHeight = res.getDimensionPixelSize(R.dimen.date_picker_month_height);
+        mDesiredDayOfWeekHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_of_week_height);
+        mDesiredDayHeight = res.getDimensionPixelSize(R.dimen.date_picker_day_height);
+        mDesiredCellWidth = res.getDimensionPixelSize(R.dimen.date_picker_day_width);
+        mDesiredDaySelectorRadius = res.getDimensionPixelSize(R.dimen.date_picker_day_selector_radius);
 
         mPrevDrawable = context.getDrawable(R.drawable.ic_chevron_left);
         mNextDrawable = context.getDrawable(R.drawable.ic_chevron_right);
@@ -400,7 +408,7 @@
         final TextPaint p = mDayOfWeekPaint;
         final int headerHeight = mMonthHeight;
         final int rowHeight = mDayOfWeekHeight;
-        final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+        final int colWidth = mCellWidth;
 
         // Text is vertically centered within the day of week height.
         final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
@@ -426,7 +434,7 @@
         final TextPaint p = mDayPaint;
         final int headerHeight = mMonthHeight + mDayOfWeekHeight;
         final int rowHeight = mDayHeight;
-        final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+        final int colWidth = mCellWidth;
 
         // Text is vertically centered within the row height.
         final float halfLineHeight = (p.ascent() + p.descent()) / 2f;
@@ -627,9 +635,9 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        final int preferredHeight = mDayHeight * mNumWeeks + mDayOfWeekHeight + mMonthHeight
-                + getPaddingTop() + getPaddingBottom();
-        final int preferredWidth = mCellWidth * DAYS_IN_WEEK
+        final int preferredHeight = mDesiredDayHeight * mNumWeeks + mDesiredDayOfWeekHeight
+                + mDesiredMonthHeight + getPaddingTop() + getPaddingBottom();
+        final int preferredWidth = mDesiredCellWidth * DAYS_IN_WEEK
                 + getPaddingStart() + getPaddingEnd();
         final int resolvedWidth = resolveSize(preferredWidth, widthMeasureSpec);
         final int resolvedHeight = resolveSize(preferredHeight, heightMeasureSpec);
@@ -637,16 +645,46 @@
     }
 
     @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        final int paddedLeft = getPaddingLeft();
-        final int paddedTop = getPaddingTop();
-        final int paddedRight = w - getPaddingRight();
-        final int paddedBottom = h - getPaddingBottom();
-        mPaddedWidth = paddedRight - paddedLeft;
-        mPaddedHeight = paddedBottom - paddedTop;
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!changed) {
+            return;
+        }
 
-        final int monthHeight = mMonthHeight;
+        // Let's initialize a completely reasonable number of variables.
+        final int w = right - left;
+        final int h = bottom - top;
+        final int paddingLeft = getPaddingLeft();
+        final int paddingTop = getPaddingTop();
+        final int paddingRight = getPaddingRight();
+        final int paddingBottom = getPaddingBottom();
+        final int paddedRight = w - paddingRight;
+        final int paddedBottom = h - paddingBottom;
+        final int paddedWidth = paddedRight - paddingLeft;
+        final int paddedHeight = paddedBottom - paddingTop;
+        if (paddedWidth == mPaddedWidth || paddedHeight == mPaddedHeight) {
+            return;
+        }
+
+        mPaddedWidth = paddedWidth;
+        mPaddedHeight = paddedHeight;
+
+        // We may have been laid out smaller than our preferred size. If so,
+        // scale all dimensions to fit.
+        final int measuredPaddedHeight = getMeasuredHeight() - paddingTop - paddingBottom;
+        final float scaleH = paddedHeight / (float) measuredPaddedHeight;
+        final int monthHeight = (int) (mDesiredMonthHeight * scaleH);
         final int cellWidth = mPaddedWidth / DAYS_IN_WEEK;
+        mMonthHeight = monthHeight;
+        mDayOfWeekHeight = (int) (mDesiredDayOfWeekHeight * scaleH);
+        mDayHeight = (int) (mDesiredDayHeight * scaleH);
+        mCellWidth = cellWidth;
+
+        // Compute the largest day selector radius that's still within the clip
+        // bounds and desired selector radius.
+        final int maxSelectorWidth = cellWidth / 2 + Math.min(paddingLeft, paddingRight);
+        final int maxSelectorHeight = mDayHeight / 2 + paddingBottom;
+        mDaySelectorRadius = Math.min(mDesiredDaySelectorRadius,
+                Math.min(maxSelectorWidth, maxSelectorHeight));
 
         // Vertically center the previous/next drawables within the month
         // header, horizontally center within the day cell, then expand the
@@ -660,7 +698,7 @@
 
             // Button bounds don't include padding, but hit area does.
             prevDrawable.setBounds(iconLeft, iconTop, iconLeft + dW, iconTop + dH);
-            mPrevHitArea.set(0, 0, paddedLeft + cellWidth, paddedTop + monthHeight);
+            mPrevHitArea.set(0, 0, paddingLeft + cellWidth, paddingTop + monthHeight);
         }
 
         final Drawable nextDrawable = mNextDrawable;
@@ -668,11 +706,11 @@
             final int dW = nextDrawable.getIntrinsicWidth();
             final int dH = nextDrawable.getIntrinsicHeight();
             final int iconTop = (monthHeight - dH) / 2;
-            final int iconRight = mPaddedWidth - (cellWidth - dW) / 2;
+            final int iconRight = paddedWidth - (cellWidth - dW) / 2;
 
             // Button bounds don't include padding, but hit area does.
             nextDrawable.setBounds(iconRight - dW, iconTop, iconRight, iconTop + dH);
-            mNextHitArea.set(paddedRight - cellWidth, 0, w, paddedTop + monthHeight);
+            mNextHitArea.set(paddedRight - cellWidth, 0, w, paddingTop + monthHeight);
         }
 
         // Invalidate cached accessibility information.
@@ -753,7 +791,7 @@
 
         // Compute left edge.
         final int col = index % DAYS_IN_WEEK;
-        final int colWidth = mPaddedWidth / DAYS_IN_WEEK;
+        final int colWidth = mCellWidth;
         final int left = getPaddingLeft() + col * colWidth;
 
         // Compute top edge.
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index bb290e7..ae779fe 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1363,8 +1363,8 @@
     }
 
     @Override
-    public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) {
-        super.onProvideAssistStructure(structure, extras);
+    public void onProvideAssistStructure(ViewAssistStructure structure) {
+        super.onProvideAssistStructure(structure);
         CharSequence switchText = isChecked() ? mTextOn : mTextOff;
         if (!TextUtils.isEmpty(switchText)) {
             CharSequence oldText = structure.getText();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 718ef93..11439e4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -543,6 +543,8 @@
     private float mSpacingMult = 1.0f;
     private float mSpacingAdd = 0.0f;
 
+    private int mBreakStrategy;
+
     private int mMaximum = Integer.MAX_VALUE;
     private int mMaxMode = LINES;
     private int mMinimum = 0;
@@ -680,6 +682,7 @@
         boolean elegant = false;
         float letterSpacing = 0;
         String fontFeatureSettings = null;
+        mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
 
         final Resources.Theme theme = context.getTheme();
 
@@ -1133,6 +1136,9 @@
             case com.android.internal.R.styleable.TextView_fontFeatureSettings:
                 fontFeatureSettings = a.getString(attr);
                 break;
+
+            case com.android.internal.R.styleable.TextView_breakStrategy:
+                mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
             }
         }
         a.recycle();
@@ -2960,6 +2966,35 @@
     }
 
     /**
+     * Sets the break strategy for breaking paragraphs into lines. The default value for
+     * TextView is {@link Layout#BREAK_STRATEGY_HIGH_QUALITY}, and the default value for
+     * EditText is {@link Layout#BREAK_STRATEGY_SIMPLE}, the latter to avoid the
+     * text "dancing" when being edited.
+     *
+     * @attr ref android.R.styleable#TextView_breakStrategy
+     * @see #getBreakStrategy()
+     */
+    public void setBreakStrategy(@Layout.BreakStrategy int breakStrategy) {
+        mBreakStrategy = breakStrategy;
+        if (mLayout != null) {
+            nullLayouts();
+            requestLayout();
+            invalidate();
+        }
+    }
+
+    /**
+     * @return the currently set break strategy.
+     *
+     * @attr ref android.R.styleable#TextView_breakStrategy
+     * @see #setBreakStrategy(int)
+     */
+    @Layout.BreakStrategy
+    public int getBreakStrategy() {
+        return mBreakStrategy;
+    }
+
+    /**
      * Sets font feature settings.  The format is the same as the CSS
      * font-feature-settings attribute:
      * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings
@@ -6492,27 +6527,25 @@
                                 hintBoring, mIncludePad, mEllipsize,
                                 ellipsisWidth);
                     }
-                } else if (shouldEllipsize) {
-                    mHintLayout = new StaticLayout(mHint,
-                                0, mHint.length(),
-                                mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
-                                mSpacingAdd, mIncludePad, mEllipsize,
-                                ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-                } else {
-                    mHintLayout = new StaticLayout(mHint, mTextPaint,
-                            hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                            mIncludePad);
                 }
-            } else if (shouldEllipsize) {
-                mHintLayout = new StaticLayout(mHint,
-                            0, mHint.length(),
-                            mTextPaint, hintWidth, alignment, mTextDir, mSpacingMult,
-                            mSpacingAdd, mIncludePad, mEllipsize,
-                            ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-            } else {
-                mHintLayout = new StaticLayout(mHint, mTextPaint,
-                        hintWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                        mIncludePad);
+            }
+            // TODO: code duplication with makeSingleLayout()
+            if (mHintLayout == null) {
+                StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
+                        mHint.length(), hintWidth)
+                        .setPaint(mTextPaint)
+                        .setAlignment(alignment)
+                        .setTextDir(mTextDir)
+                        .setSpacingMult(mSpacingMult)
+                        .setSpacingAdd(mSpacingAdd)
+                        .setIncludePad(mIncludePad)
+                        .setBreakStrategy(mBreakStrategy);
+                if (shouldEllipsize) {
+                    builder.setEllipsize(mEllipsize)
+                            .setEllipsizedWidth(ellipsisWidth)
+                            .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+                }
+                mHintLayout = builder.build();
             }
         }
 
@@ -6544,9 +6577,8 @@
         Layout result = null;
         if (mText instanceof Spannable) {
             result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
-                    alignment, mTextDir, mSpacingMult,
-                    mSpacingAdd, mIncludePad, getKeyListener() == null ? effectiveEllipsize : null,
-                            ellipsisWidth);
+                    alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
+                    getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
         } else {
             if (boring == UNKNOWN_BORING) {
                 boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir, mBoring);
@@ -6583,29 +6615,27 @@
                                 boring, mIncludePad, effectiveEllipsize,
                                 ellipsisWidth);
                     }
-                } else if (shouldEllipsize) {
-                    result = new StaticLayout(mTransformed,
-                            0, mTransformed.length(),
-                            mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
-                            mSpacingAdd, mIncludePad, effectiveEllipsize,
-                            ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-                } else {
-                    result = new StaticLayout(mTransformed, mTextPaint,
-                            wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                            mIncludePad);
                 }
-            } else if (shouldEllipsize) {
-                result = new StaticLayout(mTransformed,
-                        0, mTransformed.length(),
-                        mTextPaint, wantWidth, alignment, mTextDir, mSpacingMult,
-                        mSpacingAdd, mIncludePad, effectiveEllipsize,
-                        ellipsisWidth, mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
-            } else {
-                result = new StaticLayout(mTransformed, mTextPaint,
-                        wantWidth, alignment, mTextDir, mSpacingMult, mSpacingAdd,
-                        mIncludePad);
             }
         }
+        if (result == null) {
+            StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
+                    0, mTransformed.length(), wantWidth)
+                    .setPaint(mTextPaint)
+                    .setAlignment(alignment)
+                    .setTextDir(mTextDir)
+                    .setSpacingMult(mSpacingMult)
+                    .setSpacingAdd(mSpacingAdd)
+                    .setIncludePad(mIncludePad)
+                    .setBreakStrategy(mBreakStrategy);
+            if (shouldEllipsize) {
+                builder.setEllipsize(effectiveEllipsize)
+                        .setEllipsizedWidth(ellipsisWidth)
+                        .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+            }
+            // TODO: explore always setting maxLines
+            result = builder.build();
+        }
         return result;
     }
 
@@ -8576,8 +8606,8 @@
     }
 
     @Override
-    public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) {
-        super.onProvideAssistStructure(structure, extras);
+    public void onProvideAssistStructure(ViewAssistStructure structure) {
+        super.onProvideAssistStructure(structure);
         final boolean isPassword = hasPasswordTransformationMethod();
         if (!isPassword) {
             structure.setText(getText(), getSelectionStart(), getSelectionEnd());
@@ -9037,6 +9067,12 @@
     }
 
     boolean selectAllText() {
+        // Need to hide insert point cursor controller before settings selection, otherwise insert
+        // point cursor controller obtains cursor update event and update cursor with cancelling
+        // selection.
+        if (mEditor != null) {
+            mEditor.hideInsertionPointCursorController();
+        }
         final int length = mText.length();
         Selection.setSelection((Spannable) mText, 0, length);
         return length > 0;
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index c58d5cb..2365b48 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -25,8 +25,10 @@
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.SpannableStringBuilder;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
+import android.text.style.TtsSpan;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.StateSet;
@@ -155,13 +157,16 @@
         mHourView.setMinWidth(computeStableWidth(mHourView, 24));
         mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
 
+        final SpannableStringBuilder amLabel = new SpannableStringBuilder()
+                .append(amPmStrings[0], new TtsSpan.VerbatimBuilder(amPmStrings[0]).build(), 0);
+
         // Set up AM/PM labels.
         mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
         mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
-        mAmLabel.setText(amPmStrings[0]);
+        mAmLabel.setText(obtainVerbatim(amPmStrings[0]));
         mAmLabel.setOnClickListener(mClickListener);
         mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
-        mPmLabel.setText(amPmStrings[1]);
+        mPmLabel.setText(obtainVerbatim(amPmStrings[1]));
         mPmLabel.setOnClickListener(mClickListener);
 
         // For the sake of backwards compatibility, attempt to extract the text
@@ -220,6 +225,11 @@
         initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
     }
 
+    private static final CharSequence obtainVerbatim(String text) {
+        return new SpannableStringBuilder().append(text,
+                new TtsSpan.VerbatimBuilder(text).build(), 0);
+    }
+
     /**
      * The legacy text color might have been poorly defined. Ensures that it
      * has an appropriate activated state, using the selected state if one
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
index 7e70b0c..0ce501e 100644
--- a/core/java/com/android/internal/app/DumpHeapActivity.java
+++ b/core/java/com/android/internal/app/DumpHeapActivity.java
@@ -17,13 +17,16 @@
 package com.android.internal.app;
 
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
 import android.content.ClipData;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.DebugUtils;
+import android.util.Slog;
 
 /**
  * This activity is displayed when the system has collected a heap dump from
@@ -34,6 +37,8 @@
     public static final String KEY_PROCESS = "process";
     /** The size limit the process reached */
     public static final String KEY_SIZE = "size";
+    /** Optional name of package to directly launch */
+    public static final String KEY_DIRECT_LAUNCH = "direct_launch";
 
     // Broadcast action to determine when to delete the current dump heap data.
     public static final String ACTION_DELETE_DUMPHEAP = "com.android.server.am.DELETE_DUMPHEAP";
@@ -54,6 +59,28 @@
 
         mProcess = getIntent().getStringExtra(KEY_PROCESS);
         mSize = getIntent().getLongExtra(KEY_SIZE, 0);
+
+        String directLaunch = getIntent().getStringExtra(KEY_DIRECT_LAUNCH);
+        if (directLaunch != null) {
+            Intent intent = new Intent(ActivityManager.ACTION_REPORT_HEAP_LIMIT);
+            intent.setPackage(directLaunch);
+            ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
+            intent.setClipData(clip);
+            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            intent.setType(clip.getDescription().getMimeType(0));
+            intent.putExtra(Intent.EXTRA_STREAM, JAVA_URI);
+            try {
+                startActivity(intent);
+                scheduleDelete();
+                mHandled = true;
+                finish();
+                return;
+            } catch (ActivityNotFoundException e) {
+                Slog.i("DumpHeapActivity", "Unable to direct launch to " + directLaunch
+                        + ": " + e.getMessage());
+            }
+        }
+
         AlertDialog.Builder b = new AlertDialog.Builder(this,
                 android.R.style.Theme_Material_Light_Dialog_Alert);
         b.setTitle(com.android.internal.R.string.dump_heap_title);
@@ -71,9 +98,7 @@
             @Override
             public void onClick(DialogInterface dialog, int which) {
                 mHandled = true;
-                Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
-                broadcast.putExtra(EXTRA_DELAY_DELETE, true);
-                sendBroadcast(broadcast);
+                scheduleDelete();
                 Intent intent = new Intent(Intent.ACTION_SEND);
                 ClipData clip = ClipData.newUri(getContentResolver(), "Heap Dump", JAVA_URI);
                 intent.setClipData(clip);
@@ -88,6 +113,12 @@
         mDialog = b.show();
     }
 
+    void scheduleDelete() {
+        Intent broadcast = new Intent(ACTION_DELETE_DUMPHEAP);
+        broadcast.putExtra(EXTRA_DELAY_DELETE, true);
+        sendBroadcast(broadcast);
+    }
+
     @Override
     protected void onStop() {
         super.onStop();
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index bea4ece..4f0e29e 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -40,6 +40,9 @@
 
     ParcelFileDescriptor getStatisticsStream();
 
+    // Return true if we see the battery as currently charging.
+    boolean isCharging();
+
     // Return the computed amount of time remaining on battery, in milliseconds.
     // Returns -1 if nothing could be computed.
     long computeBatteryTimeRemaining();
@@ -109,6 +112,7 @@
     void noteWifiBatchedScanStoppedFromSource(in WorkSource ws);
     void noteWifiMulticastEnabledFromSource(in WorkSource ws);
     void noteWifiMulticastDisabledFromSource(in WorkSource ws);
+    void noteWifiRadioPowerState(int powerState, long timestampNs);
     void noteNetworkInterfaceType(String iface, int type);
     void noteNetworkStatsEnabled();
     void noteDeviceIdleMode(boolean enabled, boolean fromActive, boolean fromMotion);
diff --git a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
index 6450d52..d149c5b9 100644
--- a/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl
@@ -16,9 +16,11 @@
 
 package com.android.internal.app;
 
+import android.content.ComponentName;
 import android.content.Intent;
 import android.os.Bundle;
 
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
@@ -80,4 +82,28 @@
      */
     int stopRecognition(in IVoiceInteractionService service, int keyphraseId,
             in IRecognitionStatusCallback callback);
+
+    /**
+     * @return the component name for the currently active voice interaction service
+     */
+    ComponentName getActiveServiceComponentName();
+
+    /**
+     * Shows the session for the currently active service. Used to start a new session from system
+     * affordances.
+     *
+     * @param showCallback callback to be notified when the session was shown
+     */
+    void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback);
+
+    /**
+     * Indicates whether there is a voice session running (but not necessarily showing).
+     */
+    boolean isSessionRunning();
+
+    /**
+     * Indicates whether the currently active voice interaction service is capable of handling the
+     * assist gesture.
+     */
+    boolean activeServiceSupportsAssistGesture();
 }
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl
similarity index 81%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl
index c9fd989..15fa89b 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/core/java/com/android/internal/app/IVoiceInteractionSessionShowCallback.aidl
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package com.android.internal.app;
+
+oneway interface IVoiceInteractionSessionShowCallback {
+    void onFailed();
+    void onShown();
+}
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 1f0bb76..4efefa9 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -246,9 +246,8 @@
             IActivityManager am = ActivityManagerNative.getDefault();
             Configuration config = am.getConfiguration();
 
-            // Will set userSetLocale to indicate this isn't some passing default - the user
-            // wants this remembered
             config.setLocale(locale);
+            config.userSetLocale = true;
 
             am.updateConfiguration(config);
             // Trigger the dirty bit for the Settings Provider.
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 75beee9..fe79eff 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -140,6 +140,8 @@
             STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT
             STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
             STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
+            STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+            STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
             STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
             STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
             STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 7bdb4be..255f1fd 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -25,15 +25,16 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageParser.PackageLite;
 import android.os.Environment;
-import android.os.Environment.UserEnvironment;
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageResultCode;
+import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
+import android.util.ArraySet;
 import android.util.Log;
 
 import libcore.io.IoUtils;
@@ -335,6 +336,94 @@
 
     /**
      * Given a requested {@link PackageInfo#installLocation} and calculated
+     * install size, pick the actual volume to install the app. Only considers
+     * internal and private volumes, and prefers to keep an existing package on
+     * its current volume.
+     *
+     * @return the {@link VolumeInfo#fsUuid} to install onto, or {@code null}
+     *         for internal storage.
+     */
+    public static String resolveInstallVolume(Context context, String packageName,
+            int installLocation, long sizeBytes) throws IOException {
+        // TODO: handle existing apps installed in ASEC; currently assumes
+        // they'll end up back on internal storage
+        ApplicationInfo existingInfo = null;
+        try {
+            existingInfo = context.getPackageManager().getApplicationInfo(packageName,
+                    PackageManager.GET_UNINSTALLED_PACKAGES);
+        } catch (NameNotFoundException ignored) {
+        }
+
+        final StorageManager storageManager = context.getSystemService(StorageManager.class);
+        final boolean fitsOnInternal = fitsOnInternal(context, sizeBytes);
+
+        final ArraySet<String> allCandidates = new ArraySet<>();
+        VolumeInfo bestCandidate = null;
+        long bestCandidateAvailBytes = Long.MIN_VALUE;
+        for (VolumeInfo vol : storageManager.getVolumes()) {
+            if (vol.type == VolumeInfo.TYPE_PRIVATE && vol.state == VolumeInfo.STATE_MOUNTED) {
+                final long availBytes = storageManager.getStorageBytesUntilLow(new File(vol.path));
+                if (availBytes >= sizeBytes) {
+                    allCandidates.add(vol.fsUuid);
+                }
+                if (availBytes >= bestCandidateAvailBytes) {
+                    bestCandidate = vol;
+                    bestCandidateAvailBytes = availBytes;
+                }
+            }
+        }
+
+        // System apps always forced to internal storage
+        if (existingInfo != null && existingInfo.isSystemApp()) {
+            installLocation = PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY;
+        }
+
+        // If app expresses strong desire for internal space, honor it
+        if (installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) {
+            if (fitsOnInternal) {
+                return null;
+            } else {
+                throw new IOException("Requested internal only, but not enough space");
+            }
+        }
+
+        // If app already exists somewhere, prefer to stay on that volume
+        if (existingInfo != null) {
+            if (existingInfo.volumeUuid == null && fitsOnInternal) {
+                return null;
+            }
+            if (allCandidates.contains(existingInfo.volumeUuid)) {
+                return existingInfo.volumeUuid;
+            }
+        }
+
+        // We're left with either preferring external or auto, so just pick
+        // volume with most space
+        if (bestCandidate != null) {
+            return bestCandidate.fsUuid;
+        } else if (fitsOnInternal) {
+            return null;
+        } else {
+            throw new IOException("No special requests, but no room anywhere");
+        }
+    }
+
+    public static boolean fitsOnInternal(Context context, long sizeBytes) {
+        final StorageManager storage = context.getSystemService(StorageManager.class);
+        final File target = Environment.getDataDirectory();
+        return (sizeBytes <= storage.getStorageBytesUntilLow(target));
+    }
+
+    public static boolean fitsOnExternal(Context context, long sizeBytes) {
+        final StorageManager storage = context.getSystemService(StorageManager.class);
+        final StorageVolume primary = storage.getPrimaryVolume();
+        return (sizeBytes > 0) && !primary.isEmulated()
+                && Environment.MEDIA_MOUNTED.equals(primary.getState())
+                && sizeBytes <= storage.getStorageBytesUntilLow(primary.getPathFile());
+    }
+
+    /**
+     * Given a requested {@link PackageInfo#installLocation} and calculated
      * install size, pick the actual location to install the app.
      */
     public static int resolveInstallLocation(Context context, String packageName,
@@ -363,6 +452,7 @@
         } else if (installLocation == PackageInfo.INSTALL_LOCATION_AUTO) {
             // When app is already installed, prefer same medium
             if (existingInfo != null) {
+                // TODO: distinguish if this is external ASEC
                 if ((existingInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                     prefer = RECOMMEND_INSTALL_EXTERNAL;
                 } else {
@@ -377,30 +467,21 @@
             checkBoth = false;
         }
 
-        final boolean emulated = Environment.isExternalStorageEmulated();
-        final StorageManager storage = StorageManager.from(context);
-
         boolean fitsOnInternal = false;
         if (checkBoth || prefer == RECOMMEND_INSTALL_INTERNAL) {
-            final File target = Environment.getDataDirectory();
-            fitsOnInternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
+            fitsOnInternal = fitsOnInternal(context, sizeBytes);
         }
 
         boolean fitsOnExternal = false;
-        if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)) {
-            final File target = new UserEnvironment(UserHandle.USER_OWNER)
-                    .getExternalStorageDirectory();
-            // External is only an option when size is known
-            if (sizeBytes > 0) {
-                fitsOnExternal = (sizeBytes <= storage.getStorageBytesUntilLow(target));
-            }
+        if (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL) {
+            fitsOnExternal = fitsOnExternal(context, sizeBytes);
         }
 
         if (prefer == RECOMMEND_INSTALL_INTERNAL) {
             if (fitsOnInternal) {
                 return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
             }
-        } else if (!emulated && prefer == RECOMMEND_INSTALL_EXTERNAL) {
+        } else if (prefer == RECOMMEND_INSTALL_EXTERNAL) {
             if (fitsOnExternal) {
                 return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
             }
@@ -409,22 +490,12 @@
         if (checkBoth) {
             if (fitsOnInternal) {
                 return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
-            } else if (!emulated && fitsOnExternal) {
+            } else if (fitsOnExternal) {
                 return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
             }
         }
 
-        /*
-         * If they requested to be on the external media by default, return that
-         * the media was unavailable. Otherwise, indicate there was insufficient
-         * storage space available.
-         */
-        if (!emulated && (checkBoth || prefer == RECOMMEND_INSTALL_EXTERNAL)
-                && !Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
-            return PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE;
-        } else {
-            return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
-        }
+        return PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
     }
 
     public static long calculateInstalledSize(PackageLite pkg, boolean isForwardLocked,
diff --git a/core/java/com/android/internal/logging/EventLogTags.logtags b/core/java/com/android/internal/logging/EventLogTags.logtags
index 870d20d..b9208ff 100644
--- a/core/java/com/android/internal/logging/EventLogTags.logtags
+++ b/core/java/com/android/internal/logging/EventLogTags.logtags
@@ -5,3 +5,5 @@
 # interaction logs
 524287 sysui_view_visibility (category|1|5),(visible|1|6)
 524288 sysui_action (category|1|5)
+524290 sysui_count (name|3),(increment|1)
+524291 sysui_histogram (name|3),(bucket|1)
diff --git a/core/java/com/android/internal/logging/MetricsConstants.java b/core/java/com/android/internal/logging/MetricsConstants.java
index e5cba84..ee225a1 100644
--- a/core/java/com/android/internal/logging/MetricsConstants.java
+++ b/core/java/com/android/internal/logging/MetricsConstants.java
@@ -32,9 +32,16 @@
     public static final int ACCOUNTS_ACCOUNT_SYNC = 9;
     public static final int ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
     public static final int ACCOUNTS_MANAGE_ACCOUNTS = 11;
+    public static final int ACTION_WIFI_ADD_NETWORK = 134;
+    public static final int ACTION_WIFI_CONNECT = 135;
+    public static final int ACTION_WIFI_FORCE_SCAN = 136;
+    public static final int ACTION_WIFI_FORGET = 137;
+    public static final int ACTION_WIFI_OFF = 138;
+    public static final int ACTION_WIFI_ON = 139;
     public static final int APN = 12;
     public static final int APN_EDITOR = 13;
     public static final int APPLICATION = 16;
+    public static final int APPLICATIONS_ADVANCED = 130;
     public static final int APPLICATIONS_APP_LAUNCH = 17;
     public static final int APPLICATIONS_APP_PERMISSION = 18;
     public static final int APPLICATIONS_APP_STORAGE = 19;
@@ -85,8 +92,13 @@
     public static final int INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
     public static final int LOCATION = 63;
     public static final int LOCATION_MODE = 64;
+    public static final int LOCATION_SCANNING = 131;
     public static final int MAIN_SETTINGS = 1;
     public static final int MANAGE_APPLICATIONS = 65;
+    public static final int MANAGE_APPLICATIONS_ALL = 132;
+    public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+    public static final int MANAGE_DOMAIN_URLS = 143;
+    public static final int MANAGE_PERMISSIONS = 140;
     public static final int MASTER_CLEAR = 66;
     public static final int MASTER_CLEAR_CONFIRM = 67;
     public static final int NET_DATA_USAGE_METERED = 68;
@@ -94,10 +106,15 @@
     public static final int NFC_PAYMENT = 70;
     public static final int NOTIFICATION = 71;
     public static final int NOTIFICATION_APP_NOTIFICATION = 72;
+    public static final int NOTIFICATION_ITEM = 128;
+    public static final int NOTIFICATION_ITEM_ACTION = 129;
     public static final int NOTIFICATION_OTHER_SOUND = 73;
+    public static final int NOTIFICATION_PANEL = 127;
     public static final int NOTIFICATION_REDACTION = 74;
     public static final int NOTIFICATION_STATION = 75;
     public static final int NOTIFICATION_ZEN_MODE = 76;
+    public static final int NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+    public static final int NOTIFICATION_ZEN_MODE_PRIORITY = 141;
     public static final int OWNER_INFO = 77;
     public static final int PRINT_JOB_SETTINGS = 78;
     public static final int PRINT_SERVICE_SETTINGS = 79;
@@ -132,7 +149,6 @@
     public static final int TRUST_AGENT = 91;
     public static final int TTS_ENGINE_SETTINGS = 93;
     public static final int TTS_TEXT_TO_SPEECH = 94;
-    public static final int TYPE_UNKNOWN = 0;
     public static final int USAGE_ACCESS = 95;
     public static final int USER = 96;
     public static final int USERS_APP_RESTRICTIONS = 97;
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 9b45e34..6be6389 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -26,19 +26,9 @@
  */
 public class MetricsLogger implements MetricsConstants {
     // These constants are temporary, they should migrate to MetricsConstants.
-    public static final int APPLICATIONS_ADVANCED = 132;
-    public static final int LOCATION_SCANNING = 133;
-    public static final int MANAGE_APPLICATIONS_ALL = 134;
-    public static final int MANAGE_APPLICATIONS_NOTIFICATIONS = 135;
+    // next value is 145;
 
-    public static final int ACTION_WIFI_ADD_NETWORK = 136;
-    public static final int ACTION_WIFI_CONNECT = 137;
-    public static final int ACTION_WIFI_FORCE_SCAN = 138;
-    public static final int ACTION_WIFI_FORGET = 139;
-    public static final int ACTION_WIFI_OFF = 140;
-    public static final int ACTION_WIFI_ON = 141;
-
-    public static final int MANAGE_PERMISSIONS = 142;
+    public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
@@ -60,4 +50,14 @@
         }
         EventLogTags.writeSysuiAction(category);
     }
+
+    /** Add an integer value to the monotonically increasing counter with the given name. */
+    public static void count(Context context, String name, int value) {
+        EventLogTags.writeSysuiCount(name, value);
+    }
+
+    /** Increment the bucket with the integer label on the histogram with the given name. */
+    public static void histogram(Context context, String name, int bucket) {
+        EventLogTags.writeSysuiHistogram(name, bucket);
+    }
 }
diff --git a/core/java/com/android/internal/midi/EventScheduler.java b/core/java/com/android/internal/midi/EventScheduler.java
index 7b9a48c..506902f6 100644
--- a/core/java/com/android/internal/midi/EventScheduler.java
+++ b/core/java/com/android/internal/midi/EventScheduler.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.midi;
 
+import java.util.Iterator;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -28,7 +29,7 @@
     private static final long NANOS_PER_MILLI = 1000000;
 
     private final Object mLock = new Object();
-    private SortedMap<Long, FastEventQueue> mEventBuffer;
+    volatile private SortedMap<Long, FastEventQueue> mEventBuffer;
     private FastEventQueue mEventPool = null;
     private int mMaxPoolSize = 200;
     private boolean mClosed;
@@ -68,6 +69,7 @@
             mEventsRemoved++;
             SchedulableEvent event = mFirst;
             mFirst = event.mNext;
+            event.mNext = null;
             return event;
         }
 
@@ -87,7 +89,7 @@
      */
     public static class SchedulableEvent {
         private long mTimestamp;
-        private SchedulableEvent mNext = null;
+        volatile private SchedulableEvent mNext = null;
 
         /**
          * @param timestamp
@@ -235,6 +237,11 @@
         return event;
     }
 
+    protected void flush() {
+        // Replace our event buffer with a fresh empty one
+        mEventBuffer = new TreeMap<Long, FastEventQueue>();
+    }
+
     public void close() {
         synchronized (mLock) {
             mClosed = true;
diff --git a/core/java/com/android/internal/midi/MidiConstants.java b/core/java/com/android/internal/midi/MidiConstants.java
index 87552e4..f78f75a 100644
--- a/core/java/com/android/internal/midi/MidiConstants.java
+++ b/core/java/com/android/internal/midi/MidiConstants.java
@@ -19,7 +19,7 @@
 /**
  * MIDI related constants and static methods.
  */
-public class MidiConstants {
+public final class MidiConstants {
     public static final byte STATUS_COMMAND_MASK = (byte) 0xF0;
     public static final byte STATUS_CHANNEL_MASK = (byte) 0x0F;
 
@@ -85,4 +85,16 @@
         }
         return (goodBytes == 0);
     }
+
+    // Returns true if this command can be used for running status
+    public static boolean allowRunningStatus(int command) {
+        // only Channel Voice and Channel Mode commands can use running status
+        return (command >= STATUS_NOTE_OFF && command < STATUS_SYSTEM_EXCLUSIVE);
+    }
+
+    // Returns true if this command cancels running status
+    public static boolean cancelsRunningStatus(int command) {
+        // System Common messages cancel running status
+        return (command >= STATUS_SYSTEM_EXCLUSIVE && command <= STATUS_END_SYSEX);
+    }
 }
diff --git a/core/java/com/android/internal/midi/MidiDispatcher.java b/core/java/com/android/internal/midi/MidiDispatcher.java
index 377bc68..70e699a 100644
--- a/core/java/com/android/internal/midi/MidiDispatcher.java
+++ b/core/java/com/android/internal/midi/MidiDispatcher.java
@@ -83,4 +83,11 @@
             }
         }
     }
+
+    @Override
+    public void flush() throws IOException {
+       for (MidiReceiver receiver : mReceivers) {
+            receiver.flush();
+       }
+    }
 }
diff --git a/core/java/com/android/internal/midi/MidiEventScheduler.java b/core/java/com/android/internal/midi/MidiEventScheduler.java
index 42d70f6..4dc5838 100644
--- a/core/java/com/android/internal/midi/MidiEventScheduler.java
+++ b/core/java/com/android/internal/midi/MidiEventScheduler.java
@@ -28,16 +28,9 @@
     // Maintain a pool of scheduled events to reduce memory allocation.
     // This pool increases performance by about 14%.
     private final static int POOL_EVENT_SIZE = 16;
-
-    private final MidiReceiver[] mReceivers;
+    private MidiReceiver mReceiver = new SchedulingReceiver();
 
     private class SchedulingReceiver extends MidiReceiver {
-        private final int mPortNumber;
-
-        public SchedulingReceiver(int portNumber) {
-            mPortNumber = portNumber;
-        }
-
         /**
          * Store these bytes in the EventScheduler to be delivered at the specified
          * time.
@@ -47,14 +40,17 @@
                 throws IOException {
             MidiEvent event = createScheduledEvent(msg, offset, count, timestamp);
             if (event != null) {
-                event.portNumber = mPortNumber;
                 add(event);
             }
         }
+
+        @Override
+        public void flush() {
+            MidiEventScheduler.this.flush();
+        }
     }
 
     public static class MidiEvent extends SchedulableEvent {
-        public int portNumber;
         public int count = 0;
         public byte[] data;
 
@@ -80,17 +76,6 @@
         }
     }
 
-    public MidiEventScheduler() {
-        this(0);
-    }
-
-    public MidiEventScheduler(int portCount) {
-        mReceivers = new MidiReceiver[portCount];
-        for (int i = 0; i < portCount; i++) {
-            mReceivers[i] = new SchedulingReceiver(i);
-        }
-    }
-
     /**
      * Create an event that contains the message.
      */
@@ -132,15 +117,7 @@
      * @return the MidiReceiver
      */
     public MidiReceiver getReceiver() {
-        return mReceivers[0];
-    }
-
-    /**
-     * This MidiReceiver will write date to the scheduling buffer.
-     * @return the MidiReceiver
-     */
-    public MidiReceiver getReceiver(int portNumber) {
-        return mReceivers[portNumber];
+        return mReceiver;
     }
 
 }
diff --git a/core/java/com/android/internal/os/BatterySipper.java b/core/java/com/android/internal/os/BatterySipper.java
index 4cd959f..056b0aa 100644
--- a/core/java/com/android/internal/os/BatterySipper.java
+++ b/core/java/com/android/internal/os/BatterySipper.java
@@ -23,17 +23,25 @@
 public class BatterySipper implements Comparable<BatterySipper> {
     public int userId;
     public Uid uidObj;
-    public double value;
-    public double[] values;
+    public double totalPowerMah;
     public DrainType drainType;
 
-    // Measured in milliseconds.
-    public long usageTime;
-    public long cpuTime;
-    public long gpsTime;
-    public long wifiRunningTime;
-    public long cpuFgTime;
-    public long wakeLockTime;
+    /**
+     * Generic usage time in milliseconds.
+     */
+    public long usageTimeMs;
+
+    /**
+     * Generic power usage in mAh.
+     */
+    public double usagePowerMah;
+
+    // Subsystem usage times.
+    public long cpuTimeMs;
+    public long gpsTimeMs;
+    public long wifiRunningTimeMs;
+    public long cpuFgTimeMs;
+    public long wakeLockTimeMs;
 
     public long mobileRxPackets;
     public long mobileTxPackets;
@@ -52,12 +60,13 @@
     public String packageWithHighestDrain;
 
     // Measured in mAh (milli-ampere per hour).
-    public double wifiPower;
-    public double cpuPower;
-    public double wakeLockPower;
-    public double mobileRadioPower;
-    public double gpsPower;
-    public double sensorPower;
+    // These are included when summed.
+    public double wifiPowerMah;
+    public double cpuPowerMah;
+    public double wakeLockPowerMah;
+    public double mobileRadioPowerMah;
+    public double gpsPowerMah;
+    public double sensorPowerMah;
 
     public enum DrainType {
         IDLE,
@@ -73,17 +82,12 @@
         OVERCOUNTED
     }
 
-    public BatterySipper(DrainType drainType, Uid uid, double[] values) {
-        this.values = values;
-        if (values != null) value = values[0];
+    public BatterySipper(DrainType drainType, Uid uid, double value) {
+        this.totalPowerMah = value;
         this.drainType = drainType;
         uidObj = uid;
     }
 
-    public double[] getValues() {
-        return values;
-    }
-
     public void computeMobilemspp() {
         long packets = mobileRxPackets+mobileTxPackets;
         mobilemspp = packets > 0 ? (mobileActive / (double)packets) : 0;
@@ -101,7 +105,7 @@
             }
         }
         // Return the flipped value because we want the items in descending order
-        return Double.compare(other.value, value);
+        return Double.compare(other.totalPowerMah, totalPowerMah);
     }
 
     /**
@@ -123,11 +127,14 @@
      * Add stats from other to this BatterySipper.
      */
     public void add(BatterySipper other) {
-        cpuTime += other.cpuTime;
-        gpsTime += other.gpsTime;
-        wifiRunningTime += other.wifiRunningTime;
-        cpuFgTime += other.cpuFgTime;
-        wakeLockTime += other.wakeLockTime;
+        totalPowerMah += other.totalPowerMah;
+        usageTimeMs += other.usageTimeMs;
+        usagePowerMah += other.usagePowerMah;
+        cpuTimeMs += other.cpuTimeMs;
+        gpsTimeMs += other.gpsTimeMs;
+        wifiRunningTimeMs += other.wifiRunningTimeMs;
+        cpuFgTimeMs += other.cpuFgTimeMs;
+        wakeLockTimeMs += other.wakeLockTimeMs;
         mobileRxPackets += other.mobileRxPackets;
         mobileTxPackets += other.mobileTxPackets;
         mobileActive += other.mobileActive;
@@ -138,11 +145,20 @@
         mobileTxBytes += other.mobileTxBytes;
         wifiRxBytes += other.wifiRxBytes;
         wifiTxBytes += other.wifiTxBytes;
-        wifiPower += other.wifiPower;
-        gpsPower += other.gpsPower;
-        cpuPower += other.cpuPower;
-        sensorPower += other.sensorPower;
-        mobileRadioPower += other.mobileRadioPower;
-        wakeLockPower += other.wakeLockPower;
+        wifiPowerMah += other.wifiPowerMah;
+        gpsPowerMah += other.gpsPowerMah;
+        cpuPowerMah += other.cpuPowerMah;
+        sensorPowerMah += other.sensorPowerMah;
+        mobileRadioPowerMah += other.mobileRadioPowerMah;
+        wakeLockPowerMah += other.wakeLockPowerMah;
+    }
+
+    /**
+     * Sum all the powers and store the value into `value`.
+     * @return the sum of all the power in this BatterySipper.
+     */
+    public double sumPower() {
+        return totalPowerMah = usagePowerMah + wifiPowerMah + gpsPowerMah + cpuPowerMah + sensorPowerMah
+                + mobileRadioPowerMah + wakeLockPowerMah;
     }
 }
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index d3611bf..59dbec6 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -16,15 +16,9 @@
 
 package com.android.internal.os;
 
-import static android.os.BatteryStats.NETWORK_MOBILE_RX_DATA;
-import static android.os.BatteryStats.NETWORK_MOBILE_TX_DATA;
-import static android.os.BatteryStats.NETWORK_WIFI_RX_DATA;
-import static android.os.BatteryStats.NETWORK_WIFI_TX_DATA;
-
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.net.ConnectivityManager;
 import android.os.BatteryStats;
@@ -38,7 +32,6 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.telephony.SignalStrength;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -54,7 +47,6 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 
 /**
  * A helper class for retrieving the power usage information for all applications and services.
@@ -63,8 +55,7 @@
  * onAttach() for Fragment), call create() in onCreate() and call destroy() in onDestroy().
  */
 public final class BatteryStatsHelper {
-
-    private static final boolean DEBUG = false;
+    static final boolean DEBUG = false;
 
     private static final String TAG = BatteryStatsHelper.class.getSimpleName();
 
@@ -81,14 +72,24 @@
     private Intent mBatteryBroadcast;
     private PowerProfile mPowerProfile;
 
-    private final List<BatterySipper> mUsageList = new ArrayList<BatterySipper>();
-    private final List<BatterySipper> mWifiSippers = new ArrayList<BatterySipper>();
-    private final List<BatterySipper> mBluetoothSippers = new ArrayList<BatterySipper>();
-    private final SparseArray<List<BatterySipper>> mUserSippers
-            = new SparseArray<List<BatterySipper>>();
-    private final SparseArray<Double> mUserPower = new SparseArray<Double>();
+    /**
+     * List of apps using power.
+     */
+    private final List<BatterySipper> mUsageList = new ArrayList<>();
 
-    private final List<BatterySipper> mMobilemsppList = new ArrayList<BatterySipper>();
+    /**
+     * List of apps using wifi power.
+     */
+    private final List<BatterySipper> mWifiSippers = new ArrayList<>();
+
+    /**
+     * List of apps using bluetooth power.
+     */
+    private final List<BatterySipper> mBluetoothSippers = new ArrayList<>();
+
+    private final SparseArray<List<BatterySipper>> mUserSippers = new SparseArray<>();
+
+    private final List<BatterySipper> mMobilemsppList = new ArrayList<>();
 
     private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
 
@@ -102,29 +103,45 @@
     long mChargeTimeRemaining;
 
     private long mStatsPeriod = 0;
+
+    // The largest entry by power.
     private double mMaxPower = 1;
+
+    // The largest real entry by power (not undercounted or overcounted).
     private double mMaxRealPower = 1;
+
+    // Total computed power.
     private double mComputedPower;
     private double mTotalPower;
-    private double mWifiPower;
-    private double mBluetoothPower;
     private double mMinDrainedPower;
     private double mMaxDrainedPower;
 
-    // How much the apps together have kept the mobile radio active.
-    private long mAppMobileActive;
+    PowerCalculator mCpuPowerCalculator;
+    PowerCalculator mWakelockPowerCalculator;
+    MobileRadioPowerCalculator mMobileRadioPowerCalculator;
+    PowerCalculator mWifiPowerCalculator;
+    PowerCalculator mBluetoothPowerCalculator;
+    PowerCalculator mSensorPowerCalculator;
 
-    // How much the apps together have left WIFI running.
-    private long mAppWifiRunning;
+    public static boolean checkWifiOnly(Context context) {
+        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+    }
+
+    public static boolean checkHasWifiPowerReporting(BatteryStats stats, PowerProfile profile) {
+        return stats.hasWifiActivityReporting() &&
+                profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE) != 0 &&
+                profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX) != 0 &&
+                profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX) != 0;
+    }
 
     public BatteryStatsHelper(Context context) {
         this(context, true);
     }
 
     public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast) {
-        mContext = context;
-        mCollectBatteryBroadcast = collectBatteryBroadcast;
-        mWifiOnly = checkWifiOnly(context);
+        this(context, collectBatteryBroadcast, checkWifiOnly(context));
     }
 
     public BatteryStatsHelper(Context context, boolean collectBatteryBroadcast, boolean wifiOnly) {
@@ -133,12 +150,6 @@
         mWifiOnly = wifiOnly;
     }
 
-    public static boolean checkWifiOnly(Context context) {
-        ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
-        return !cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
-    }
-
     public void storeStatsHistoryInFile(String fname) {
         synchronized (sFileXfer) {
             File path = makeFilePath(mContext, fname);
@@ -260,7 +271,7 @@
      * Refreshes the power usage list.
      */
     public void refreshStats(int statsType, int asUser) {
-        SparseArray<UserHandle> users = new SparseArray<UserHandle>(1);
+        SparseArray<UserHandle> users = new SparseArray<>(1);
         users.put(asUser, new UserHandle(asUser));
         refreshStats(statsType, users);
     }
@@ -270,7 +281,7 @@
      */
     public void refreshStats(int statsType, List<UserHandle> asUsers) {
         final int n = asUsers.size();
-        SparseArray<UserHandle> users = new SparseArray<UserHandle>(n);
+        SparseArray<UserHandle> users = new SparseArray<>(n);
         for (int i = 0; i < n; ++i) {
             UserHandle userHandle = asUsers.get(i);
             users.put(userHandle.getIdentifier(), userHandle);
@@ -295,22 +306,52 @@
         mMaxRealPower = 0;
         mComputedPower = 0;
         mTotalPower = 0;
-        mWifiPower = 0;
-        mBluetoothPower = 0;
-        mAppMobileActive = 0;
-        mAppWifiRunning = 0;
 
         mUsageList.clear();
         mWifiSippers.clear();
         mBluetoothSippers.clear();
         mUserSippers.clear();
-        mUserPower.clear();
         mMobilemsppList.clear();
 
         if (mStats == null) {
             return;
         }
 
+        if (mCpuPowerCalculator == null) {
+            mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+        }
+        mCpuPowerCalculator.reset();
+
+        if (mWakelockPowerCalculator == null) {
+            mWakelockPowerCalculator = new WakelockPowerCalculator(mPowerProfile);
+        }
+        mWakelockPowerCalculator.reset();
+
+        if (mMobileRadioPowerCalculator == null) {
+            mMobileRadioPowerCalculator = new MobileRadioPowerCalculator(mPowerProfile, mStats);
+        }
+        mMobileRadioPowerCalculator.reset(mStats);
+
+        if (mWifiPowerCalculator == null) {
+            if (checkHasWifiPowerReporting(mStats, mPowerProfile)) {
+                mWifiPowerCalculator = new WifiPowerCalculator(mPowerProfile);
+            } else {
+                mWifiPowerCalculator = new WifiPowerEstimator(mPowerProfile);
+            }
+        }
+        mWifiPowerCalculator.reset();
+
+        if (mBluetoothPowerCalculator == null) {
+            mBluetoothPowerCalculator = new BluetoothPowerCalculator();
+        }
+        mBluetoothPowerCalculator.reset();
+
+        if (mSensorPowerCalculator == null) {
+            mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
+                    (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE));
+        }
+        mSensorPowerCalculator.reset();
+
         mStatsType = statsType;
         mRawUptime = rawUptimeUs;
         mRawRealtime = rawRealtimeUs;
@@ -358,383 +399,113 @@
         Collections.sort(mMobilemsppList, new Comparator<BatterySipper>() {
             @Override
             public int compare(BatterySipper lhs, BatterySipper rhs) {
-                if (lhs.mobilemspp < rhs.mobilemspp) {
-                    return 1;
-                } else if (lhs.mobilemspp > rhs.mobilemspp) {
-                    return -1;
-                }
-                return 0;
+                return Double.compare(rhs.mobilemspp, lhs.mobilemspp);
             }
         });
 
         processMiscUsage();
 
+        Collections.sort(mUsageList);
+
+        // At this point, we've sorted the list so we are guaranteed the max values are at the top.
+        // We have only added real powers so far.
+        if (!mUsageList.isEmpty()) {
+            mMaxRealPower = mMaxPower = mUsageList.get(0).totalPowerMah;
+            final int usageListCount = mUsageList.size();
+            for (int i = 0; i < usageListCount; i++) {
+                mComputedPower += mUsageList.get(i).totalPowerMah;
+            }
+        }
+
         if (DEBUG) {
             Log.d(TAG, "Accuracy: total computed=" + makemAh(mComputedPower) + ", min discharge="
                     + makemAh(mMinDrainedPower) + ", max discharge=" + makemAh(mMaxDrainedPower));
         }
+
         mTotalPower = mComputedPower;
         if (mStats.getLowDischargeAmountSinceCharge() > 1) {
             if (mMinDrainedPower > mComputedPower) {
                 double amount = mMinDrainedPower - mComputedPower;
                 mTotalPower = mMinDrainedPower;
-                addEntryNoTotal(BatterySipper.DrainType.UNACCOUNTED, 0, amount);
+                BatterySipper bs = new BatterySipper(DrainType.UNACCOUNTED, null, amount);
+
+                // Insert the BatterySipper in its sorted position.
+                int index = Collections.binarySearch(mUsageList, bs);
+                if (index < 0) {
+                    index = -(index + 1);
+                }
+                mUsageList.add(index, bs);
+                mMaxPower = Math.max(mMaxPower, amount);
             } else if (mMaxDrainedPower < mComputedPower) {
                 double amount = mComputedPower - mMaxDrainedPower;
-                addEntryNoTotal(BatterySipper.DrainType.OVERCOUNTED, 0, amount);
+
+                // Insert the BatterySipper in its sorted position.
+                BatterySipper bs = new BatterySipper(DrainType.OVERCOUNTED, null, amount);
+                int index = Collections.binarySearch(mUsageList, bs);
+                if (index < 0) {
+                    index = -(index + 1);
+                }
+                mUsageList.add(index, bs);
+                mMaxPower = Math.max(mMaxPower, amount);
             }
         }
-
-        Collections.sort(mUsageList);
     }
 
     private void processAppUsage(SparseArray<UserHandle> asUsers) {
         final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
-        final SensorManager sensorManager =
-                (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
-        final int which = mStatsType;
-        final int speedSteps = mPowerProfile.getNumSpeedSteps();
-        final double[] powerCpuNormal = new double[speedSteps];
-        final long[] cpuSpeedStepTimes = new long[speedSteps];
-        for (int p = 0; p < speedSteps; p++) {
-            powerCpuNormal[p] = mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
-        }
-        final double mobilePowerPerPacket = getMobilePowerPerPacket();
-        final double mobilePowerPerMs = getMobilePowerPerMs();
-        final double wifiPowerPerPacket = getWifiPowerPerPacket();
-        long totalAppWakelockTimeUs = 0;
-        BatterySipper osApp = null;
         mStatsPeriod = mTypeBatteryRealtime;
 
-        final ArrayList<BatterySipper> appList = new ArrayList<>();
-
-        // Max values used to normalize later.
-        double maxWifiPower = 0;
-        double maxCpuPower = 0;
-        double maxWakeLockPower = 0;
-        double maxMobileRadioPower = 0;
-        double maxGpsPower = 0;
-        double maxSensorPower = 0;
-
         final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
         final int NU = uidStats.size();
         for (int iu = 0; iu < NU; iu++) {
             final Uid u = uidStats.valueAt(iu);
-            final BatterySipper app = new BatterySipper(
-                    BatterySipper.DrainType.APP, u, new double[]{0});
+            final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
 
-            final Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
-            if (processStats.size() > 0) {
-                // Process CPU time.
+            mCpuPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
 
-                // Keep track of the package with highest drain.
-                double highestDrain = 0;
-
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
-                        : processStats.entrySet()) {
-                    Uid.Proc ps = ent.getValue();
-                    app.cpuFgTime += ps.getForegroundTime(which);
-                    final long totalCpuTime = ps.getUserTime(which) + ps.getSystemTime(which);
-                    app.cpuTime += totalCpuTime;
-
-                    // Calculate the total CPU time spent at the various speed steps.
-                    long totalTimeAtSpeeds = 0;
-                    for (int step = 0; step < speedSteps; step++) {
-                        cpuSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, which);
-                        totalTimeAtSpeeds += cpuSpeedStepTimes[step];
-                    }
-                    totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
-
-                    // Then compute the ratio of time spent at each speed and figure out
-                    // the total power consumption.
-                    double cpuPower = 0;
-                    for (int step = 0; step < speedSteps; step++) {
-                        final double ratio = (double) cpuSpeedStepTimes[step] / totalTimeAtSpeeds;
-                        final double cpuSpeedStepPower =
-                                ratio * totalCpuTime * powerCpuNormal[step];
-                        if (DEBUG && ratio != 0) {
-                            Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
-                                    + step + " ratio=" + makemAh(ratio) + " power="
-                                    + makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
-                        }
-                        cpuPower += cpuSpeedStepPower;
-                    }
-
-                    if (DEBUG && cpuPower != 0) {
-                        Log.d(TAG, String.format("process %s, cpu power=%s",
-                                ent.getKey(), makemAh(cpuPower / (60 * 60 * 1000))));
-                    }
-                    app.cpuPower += cpuPower;
-
-                    // Each App can have multiple packages and with multiple running processes.
-                    // Keep track of the package who's process has the highest drain.
-                    if (app.packageWithHighestDrain == null ||
-                            app.packageWithHighestDrain.startsWith("*")) {
-                        highestDrain = cpuPower;
-                        app.packageWithHighestDrain = ent.getKey();
-                    } else if (highestDrain < cpuPower && !ent.getKey().startsWith("*")) {
-                        highestDrain = cpuPower;
-                        app.packageWithHighestDrain = ent.getKey();
-                    }
-                }
-            }
-
-            // Ensure that the CPU times make sense.
-            if (app.cpuFgTime > app.cpuTime) {
-                if (DEBUG && app.cpuFgTime > app.cpuTime + 10000) {
-                    Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
-                }
-
-                // Statistics may not have been gathered yet.
-                app.cpuTime = app.cpuFgTime;
-            }
-
-            // Convert the CPU power to mAh
-            app.cpuPower /= (60 * 60 * 1000);
-            maxCpuPower = Math.max(maxCpuPower, app.cpuPower);
-
-            // Process wake lock usage
-            final Map<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
-                    u.getWakelockStats();
-            long wakeLockTimeUs = 0;
-            for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> wakelockEntry
-                    : wakelockStats.entrySet()) {
-                final Uid.Wakelock wakelock = wakelockEntry.getValue();
-
-                // Only care about partial wake locks since full wake locks
-                // are canceled when the user turns the screen off.
-                BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
-                if (timer != null) {
-                    wakeLockTimeUs += timer.getTotalTimeLocked(mRawRealtime, which);
-                }
-            }
-            app.wakeLockTime = wakeLockTimeUs / 1000; // convert to millis
-            totalAppWakelockTimeUs += wakeLockTimeUs;
-
-            // Add cost of holding a wake lock.
-            app.wakeLockPower = (app.wakeLockTime *
-                    mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE)) / (60 * 60 * 1000);
-            if (DEBUG && app.wakeLockPower != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": wake "
-                        + app.wakeLockTime + " power=" + makemAh(app.wakeLockPower));
-            }
-            maxWakeLockPower = Math.max(maxWakeLockPower, app.wakeLockPower);
-
-            // Add cost of mobile traffic.
-            final long mobileActive = u.getMobileRadioActiveTime(mStatsType);
-            app.mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
-            app.mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
-            app.mobileActive = mobileActive / 1000;
-            app.mobileActiveCount = u.getMobileRadioActiveCount(mStatsType);
-            app.mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, mStatsType);
-            app.mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, mStatsType);
-
-            if (mobileActive > 0) {
-                // We are tracking when the radio is up, so can use the active time to
-                // determine power use.
-                mAppMobileActive += mobileActive;
-                app.mobileRadioPower = (mobilePowerPerMs * mobileActive) / 1000;
-            } else {
-                // We are not tracking when the radio is up, so must approximate power use
-                // based on the number of packets.
-                app.mobileRadioPower = (app.mobileRxPackets + app.mobileTxPackets)
-                        * mobilePowerPerPacket;
-            }
-            if (DEBUG && app.mobileRadioPower != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
-                        + (app.mobileRxPackets + app.mobileTxPackets)
-                        + " active time " + mobileActive
-                        + " power=" + makemAh(app.mobileRadioPower));
-            }
-            maxMobileRadioPower = Math.max(maxMobileRadioPower, app.mobileRadioPower);
-
-            // Add cost of wifi traffic
-            app.wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, mStatsType);
-            app.wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, mStatsType);
-            app.wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, mStatsType);
-            app.wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, mStatsType);
-
-            final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
-                    * wifiPowerPerPacket;
-            if (DEBUG && wifiPacketPower != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": wifi packets "
-                        + (app.wifiRxPackets + app.wifiTxPackets)
-                        + " power=" + makemAh(wifiPacketPower));
-            }
-
-            // Add cost of keeping WIFI running.
-            app.wifiRunningTime = u.getWifiRunningTime(mRawRealtime, which) / 1000;
-            mAppWifiRunning += app.wifiRunningTime;
-
-            final double wifiLockPower = (app.wifiRunningTime
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60 * 60 * 1000);
-            if (DEBUG && wifiLockPower != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": wifi running "
-                        + app.wifiRunningTime + " power=" + makemAh(wifiLockPower));
-            }
-
-            // Add cost of WIFI scans
-            final long wifiScanTimeMs = u.getWifiScanTime(mRawRealtime, which) / 1000;
-            final double wifiScanPower = (wifiScanTimeMs
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_SCAN))
-                    /  (60 * 60 * 1000);
-            if (DEBUG && wifiScanPower != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": wifi scan " + wifiScanTimeMs
-                        + " power=" + makemAh(wifiScanPower));
-            }
-
-            // Add cost of WIFI batch scans.
-            double wifiBatchScanPower = 0;
-            for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
-                final long batchScanTimeMs =
-                        u.getWifiBatchedScanTime(bin, mRawRealtime, which) / 1000;
-                final double batchScanPower = ((batchScanTimeMs
-                        * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN, bin))
-                ) / (60 * 60 * 1000);
-                if (DEBUG && batchScanPower != 0) {
-                    Log.d(TAG, "UID " + u.getUid() + ": wifi batched scan # " + bin
-                            + " time=" + batchScanTimeMs + " power=" + makemAh(batchScanPower));
-                }
-                wifiBatchScanPower += batchScanPower;
-            }
-
-            // Add up all the WiFi costs.
-            app.wifiPower = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
-            maxWifiPower = Math.max(maxWifiPower, app.wifiPower);
-
-            // Process Sensor usage
-            final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
-            final int NSE = sensorStats.size();
-            for (int ise = 0; ise < NSE; ise++) {
-                final Uid.Sensor sensor = sensorStats.valueAt(ise);
-                final int sensorHandle = sensorStats.keyAt(ise);
-                final BatteryStats.Timer timer = sensor.getSensorTime();
-                final long sensorTime = timer.getTotalTimeLocked(mRawRealtime, which) / 1000;
-                double sensorPower = 0;
-                switch (sensorHandle) {
-                    case Uid.Sensor.GPS:
-                        app.gpsTime = sensorTime;
-                        app.gpsPower = (app.gpsTime
-                                * mPowerProfile.getAveragePower(PowerProfile.POWER_GPS_ON))
-                                / (60 * 60 * 1000);
-                        sensorPower = app.gpsPower;
-                        maxGpsPower = Math.max(maxGpsPower, app.gpsPower);
-                        break;
-                    default:
-                        List<Sensor> sensorList = sensorManager.getSensorList(
-                                android.hardware.Sensor.TYPE_ALL);
-                        for (android.hardware.Sensor s : sensorList) {
-                            if (s.getHandle() == sensorHandle) {
-                                sensorPower = (sensorTime * s.getPower()) / (60 * 60 * 1000);
-                                app.sensorPower += sensorPower;
-                                break;
-                            }
-                        }
-                }
-                if (DEBUG && sensorPower != 0) {
-                    Log.d(TAG, "UID " + u.getUid() + ": sensor #" + sensorHandle
-                            + " time=" + sensorTime + " power=" + makemAh(sensorPower));
-                }
-            }
-            maxSensorPower = Math.max(maxSensorPower, app.sensorPower);
-
-            final double totalUnnormalizedPower = app.cpuPower + app.wifiPower + app.wakeLockPower
-                    + app.mobileRadioPower + app.gpsPower + app.sensorPower;
-            if (DEBUG && totalUnnormalizedPower != 0) {
-                Log.d(TAG, String.format("UID %d: total power=%s",
-                        u.getUid(), makemAh(totalUnnormalizedPower)));
+            final double totalPower = app.sumPower();
+            if (DEBUG && totalPower != 0) {
+                Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(),
+                        makemAh(totalPower)));
             }
 
             // Add the app to the list if it is consuming power.
-            if (totalUnnormalizedPower != 0 || u.getUid() == 0) {
-                appList.add(app);
-            }
-        }
-
-        // Fetch real power consumption from hardware.
-        double actualTotalWifiPower = 0.0;
-        if (mStats.getWifiControllerActivity(BatteryStats.CONTROLLER_ENERGY, mStatsType) != 0) {
-            final double kDefaultVoltage = 3.36;
-            final long energy = mStats.getWifiControllerActivity(
-                    BatteryStats.CONTROLLER_ENERGY, mStatsType);
-            final double voltage = mPowerProfile.getAveragePowerOrDefault(
-                    PowerProfile.OPERATING_VOLTAGE_WIFI, kDefaultVoltage);
-            actualTotalWifiPower = energy / (voltage * 1000*60*60);
-        }
-
-        final int appCount = appList.size();
-        for (int i = 0; i < appCount; i++) {
-            // Normalize power where possible.
-            final BatterySipper app = appList.get(i);
-            if (actualTotalWifiPower != 0) {
-                app.wifiPower = (app.wifiPower / maxWifiPower) * actualTotalWifiPower;
-            }
-
-            // Assign the final power consumption here.
-            final double power = app.wifiPower + app.cpuPower + app.wakeLockPower
-                    + app.mobileRadioPower + app.gpsPower + app.sensorPower;
-            app.values[0] = app.value = power;
-
-            //
-            // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
-            //
-
-            final int uid = app.getUid();
-            final int userId = UserHandle.getUserId(uid);
-            if (uid == Process.WIFI_UID) {
-                mWifiSippers.add(app);
-                mWifiPower += power;
-            } else if (uid == Process.BLUETOOTH_UID) {
-                mBluetoothSippers.add(app);
-                mBluetoothPower += power;
-            } else if (!forAllUsers && asUsers.get(userId) == null
-                    && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
-                // We are told to just report this user's apps as one large entry.
-                List<BatterySipper> list = mUserSippers.get(userId);
-                if (list == null) {
-                    list = new ArrayList<>();
-                    mUserSippers.put(userId, list);
-                }
-                list.add(app);
-
-                Double userPower = mUserPower.get(userId);
-                if (userPower == null) {
-                    userPower = power;
+            if (totalPower != 0 || u.getUid() == 0) {
+                //
+                // Add the app to the app list, WiFi, Bluetooth, etc, or into "Other Users" list.
+                //
+                final int uid = app.getUid();
+                final int userId = UserHandle.getUserId(uid);
+                if (uid == Process.WIFI_UID) {
+                    mWifiSippers.add(app);
+                } else if (uid == Process.BLUETOOTH_UID) {
+                    mBluetoothSippers.add(app);
+                } else if (!forAllUsers && asUsers.get(userId) == null
+                        && UserHandle.getAppId(uid) >= Process.FIRST_APPLICATION_UID) {
+                    // We are told to just report this user's apps as one large entry.
+                    List<BatterySipper> list = mUserSippers.get(userId);
+                    if (list == null) {
+                        list = new ArrayList<>();
+                        mUserSippers.put(userId, list);
+                    }
+                    list.add(app);
                 } else {
-                    userPower += power;
+                    mUsageList.add(app);
                 }
-                mUserPower.put(userId, userPower);
-            } else {
-                mUsageList.add(app);
-                if (power > mMaxPower) mMaxPower = power;
-                if (power > mMaxRealPower) mMaxRealPower = power;
-                mComputedPower += power;
-            }
 
-            if (uid == 0) {
-                osApp = app;
-            }
-        }
-
-        // The device has probably been awake for longer than the screen on
-        // time and application wake lock time would account for.  Assign
-        // this remainder to the OS, if possible.
-        if (osApp != null) {
-            long wakeTimeMillis = mBatteryUptime / 1000;
-            wakeTimeMillis -= (totalAppWakelockTimeUs / 1000)
-                    + (mStats.getScreenOnTime(mRawRealtime, which) / 1000);
-            if (wakeTimeMillis > 0) {
-                double power = (wakeTimeMillis
-                        * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE))
-                        /  (60*60*1000);
-                if (DEBUG) Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power "
-                        + makemAh(power));
-                osApp.wakeLockTime += wakeTimeMillis;
-                osApp.value += power;
-                osApp.values[0] += power;
-                if (osApp.value > mMaxPower) mMaxPower = osApp.value;
-                if (osApp.value > mMaxRealPower) mMaxRealPower = osApp.value;
-                mComputedPower += power;
+                if (uid == 0) {
+                    // The device has probably been awake for longer than the screen on
+                    // time and application wake lock time would account for.  Assign
+                    // this remainder to the OS, if possible.
+                    mWakelockPowerCalculator.calculateRemaining(app, mStats, mRawRealtime,
+                                                                mRawUptime, mStatsType);
+                    app.sumPower();
+                }
             }
         }
     }
@@ -744,7 +515,7 @@
         double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
                 * phoneOnTimeMs / (60*60*1000);
         if (phoneOnPower != 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
+            addEntry(BatterySipper.DrainType.PHONE, phoneOnTimeMs, phoneOnPower);
         }
     }
 
@@ -773,54 +544,19 @@
     }
 
     private void addRadioUsage() {
-        double power = 0;
-        final int BINS = SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
-        long signalTimeMs = 0;
-        long noCoverageTimeMs = 0;
-        for (int i = 0; i < BINS; i++) {
-            long strengthTimeMs = mStats.getPhoneSignalStrengthTime(i, mRawRealtime, mStatsType)
-                    / 1000;
-            double p = (strengthTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ON, i))
-                        / (60*60*1000);
-            if (DEBUG && p != 0) {
-                Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
-                        + makemAh(p));
-            }
-            power += p;
-            signalTimeMs += strengthTimeMs;
-            if (i == 0) {
-                noCoverageTimeMs = strengthTimeMs;
-            }
-        }
-        long scanningTimeMs = mStats.getPhoneSignalScanningTime(mRawRealtime, mStatsType)
-                / 1000;
-        double p = (scanningTimeMs * mPowerProfile.getAveragePower(
-                        PowerProfile.POWER_RADIO_SCANNING))
-                        / (60*60*1000);
-        if (DEBUG && p != 0) {
-            Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs + " power=" + makemAh(p));
-        }
-        power += p;
-        long radioActiveTimeUs = mStats.getMobileRadioActiveTime(mRawRealtime, mStatsType);
-        long remainingActiveTime = (radioActiveTimeUs - mAppMobileActive) / 1000;
-        if (remainingActiveTime > 0) {
-            power += getMobilePowerPerMs() * remainingActiveTime;
-        }
-        if (power != 0) {
-            BatterySipper bs =
-                    addEntry(BatterySipper.DrainType.CELL, signalTimeMs, power);
-            if (signalTimeMs != 0) {
-                bs.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
-            }
-            bs.mobileActive = remainingActiveTime;
-            bs.mobileActiveCount = mStats.getMobileRadioActiveUnknownCount(mStatsType);
+        BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
+        mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtime, mRawUptime,
+                mStatsType);
+        radio.sumPower();
+        if (radio.totalPowerMah > 0) {
+            mUsageList.add(radio);
         }
     }
 
     private void aggregateSippers(BatterySipper bs, List<BatterySipper> from, String tag) {
         for (int i=0; i<from.size(); i++) {
             BatterySipper wbs = from.get(i);
-            if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTime);
+            if (DEBUG) Log.d(TAG, tag + " adding sipper " + wbs + ": cpu=" + wbs.cpuTimeMs);
             bs.add(wbs);
         }
         bs.computeMobilemspp();
@@ -847,41 +583,12 @@
      * of WiFi to the WiFi subsystem.
      */
     private void addWiFiUsage() {
-        final long idleTimeMs = mStats.getWifiControllerActivity(
-                BatteryStats.CONTROLLER_IDLE_TIME, mStatsType);
-        final long txTimeMs = mStats.getWifiControllerActivity(
-                BatteryStats.CONTROLLER_TX_TIME, mStatsType);
-        final long rxTimeMs = mStats.getWifiControllerActivity(
-                BatteryStats.CONTROLLER_RX_TIME, mStatsType);
-        final long energy = mStats.getWifiControllerActivity(
-                BatteryStats.CONTROLLER_ENERGY, mStatsType);
-        final long totalTimeRunning = idleTimeMs + txTimeMs + rxTimeMs;
-
-        double powerDrain = 0;
-        if (energy == 0 && totalTimeRunning > 0) {
-            // Energy is not reported, which means we may have left over power drain not attributed
-            // to any app. Assign this power to the WiFi app.
-            // TODO(adamlesinski): This mimics the old behavior. However, mAppWifiRunningTime
-            // is the accumulation of the time each app kept the WiFi chip on. Multiple apps
-            // can do this at the same time, so these times do not add up to the total time
-            // the WiFi chip was on. Consider normalizing the time spent running and calculating
-            // power from that? Normalizing the times will assign a weight to each app which
-            // should better represent power usage.
-            powerDrain = ((totalTimeRunning - mAppWifiRunning)
-                    * mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ON)) / (60*60*1000);
-        }
-
-        if (DEBUG && powerDrain != 0) {
-            Log.d(TAG, "Wifi active: time=" + (txTimeMs + rxTimeMs)
-                    + " power=" + makemAh(powerDrain));
-        }
-
-        // TODO(adamlesinski): mWifiPower is already added as a BatterySipper...
-        // Are we double counting here?
-        final double power = mWifiPower + powerDrain;
-        if (power > 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.WIFI, totalTimeRunning, power);
+        BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0);
+        mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType);
+        bs.sumPower();
+        if (bs.totalPowerMah > 0 || !mWifiSippers.isEmpty()) {
             aggregateSippers(bs, mWifiSippers, "WIFI");
+            mUsageList.add(bs);
         }
     }
 
@@ -890,30 +597,10 @@
      * Bluetooth Category.
      */
     private void addBluetoothUsage() {
-        final double kDefaultVoltage = 3.36;
-        final long idleTimeMs = mStats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_IDLE_TIME, mStatsType);
-        final long txTimeMs = mStats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_TX_TIME, mStatsType);
-        final long rxTimeMs = mStats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_RX_TIME, mStatsType);
-        final long energy = mStats.getBluetoothControllerActivity(
-                BatteryStats.CONTROLLER_ENERGY, mStatsType);
-        final double voltage = mPowerProfile.getAveragePowerOrDefault(
-                PowerProfile.OPERATING_VOLTAGE_BLUETOOTH, kDefaultVoltage);
-
-        // energy is measured in mA * V * ms, and we are interested in mAh
-        final double powerDrain = energy / (voltage * 60*60*1000);
-
-        if (DEBUG && powerDrain != 0) {
-            Log.d(TAG, "Bluetooth active: time=" + (txTimeMs + rxTimeMs)
-                    + " power=" + makemAh(powerDrain));
-        }
-
-        final long totalTime = idleTimeMs + txTimeMs + rxTimeMs;
-        final double power = mBluetoothPower + powerDrain;
-        if (power > 0) {
-            BatterySipper bs = addEntry(BatterySipper.DrainType.BLUETOOTH, totalTime, power);
+        BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
+        mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime,
+                mStatsType);
+        if (bs.sumPower() > 0) {
             aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
         }
     }
@@ -928,55 +615,16 @@
     }
 
     private void addUserUsage() {
-        for (int i=0; i<mUserSippers.size(); i++) {
+        for (int i = 0; i < mUserSippers.size(); i++) {
             final int userId = mUserSippers.keyAt(i);
-            final List<BatterySipper> sippers = mUserSippers.valueAt(i);
-            Double userPower = mUserPower.get(userId);
-            double power = (userPower != null) ? userPower : 0.0;
-            BatterySipper bs = addEntry(BatterySipper.DrainType.USER, 0, power);
+            BatterySipper bs = new BatterySipper(DrainType.USER, null, 0);
             bs.userId = userId;
-            aggregateSippers(bs, sippers, "User");
+            aggregateSippers(bs, mUserSippers.valueAt(i), "User");
+            bs.sumPower();
+            mUsageList.add(bs);
         }
     }
 
-    /**
-     * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio.
-     */
-    private double getMobilePowerPerPacket() {
-        final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system
-        final double MOBILE_POWER = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
-                / 3600;
-
-        final long mobileRx = mStats.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, mStatsType);
-        final long mobileTx = mStats.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, mStatsType);
-        final long mobileData = mobileRx + mobileTx;
-
-        final long radioDataUptimeMs
-                = mStats.getMobileRadioActiveTime(mRawRealtime, mStatsType) / 1000;
-        final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
-                ? (mobileData / (double)radioDataUptimeMs)
-                : (((double)MOBILE_BPS) / 8 / 2048);
-
-        return (MOBILE_POWER / mobilePps) / (60*60);
-    }
-
-    /**
-     * Return estimated power (in mAs) of keeping the radio up
-     */
-    private double getMobilePowerPerMs() {
-        return mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE) / (60*60*1000);
-    }
-
-    /**
-     * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio.
-     */
-    private double getWifiPowerPerPacket() {
-        final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
-        final double WIFI_POWER = mPowerProfile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
-                / 3600;
-        return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60);
-    }
-
     private void processMiscUsage() {
         addUserUsage();
         addPhoneUsage();
@@ -992,15 +640,10 @@
     }
 
     private BatterySipper addEntry(DrainType drainType, long time, double power) {
-        mComputedPower += power;
-        if (power > mMaxRealPower) mMaxRealPower = power;
-        return addEntryNoTotal(drainType, time, power);
-    }
-
-    private BatterySipper addEntryNoTotal(DrainType drainType, long time, double power) {
-        if (power > mMaxPower) mMaxPower = power;
-        BatterySipper bs = new BatterySipper(drainType, null, new double[] {power});
-        bs.usageTime = time;
+        BatterySipper bs = new BatterySipper(drainType, null, 0);
+        bs.usagePowerMah = power;
+        bs.usageTimeMs = time;
+        bs.sumPower();
         mUsageList.add(bs);
         return bs;
     }
@@ -1015,7 +658,7 @@
 
     public long getStatsPeriod() { return mStatsPeriod; }
 
-    public int getStatsType() { return mStatsType; };
+    public int getStatsType() { return mStatsType; }
 
     public double getMaxPower() { return mMaxPower; }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 93dc995..fbb2dfc 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -22,6 +22,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.content.Context;
+import android.content.Intent;
 import android.net.ConnectivityManager;
 import android.net.NetworkStats;
 import android.net.wifi.WifiActivityEnergyInfo;
@@ -55,6 +56,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.SparseLongArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 import android.view.Display;
@@ -95,6 +97,7 @@
 public final class BatteryStatsImpl extends BatteryStats {
     private static final String TAG = "BatteryStatsImpl";
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_ENERGY = false;
     private static final boolean DEBUG_HISTORY = false;
     private static final boolean USE_OLD_HISTORY = false;   // for debugging.
 
@@ -104,7 +107,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 123 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -125,6 +128,7 @@
 
     static final int MSG_UPDATE_WAKELOCKS = 1;
     static final int MSG_REPORT_POWER_CHANGE = 2;
+    static final int MSG_REPORT_CHARGING = 3;
     static final long DELAY_UPDATE_WAKELOCKS = 5*1000;
 
     private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
@@ -133,6 +137,7 @@
     public interface BatteryCallback {
         public void batteryNeedsCpuUpdate();
         public void batteryPowerChanged(boolean onBattery);
+        public void batterySendBroadcast(Intent intent);
     }
 
     final class MyHandler extends Handler {
@@ -154,6 +159,18 @@
                         cb.batteryPowerChanged(msg.arg1 != 0);
                     }
                     break;
+                case MSG_REPORT_CHARGING:
+                    if (cb != null) {
+                        final String action;
+                        synchronized (BatteryStatsImpl.this) {
+                            action = mCharging ? BatteryManager.ACTION_CHARGING
+                                    : BatteryManager.ACTION_DISCHARGING;
+                        }
+                        Intent intent = new Intent(action);
+                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+                        cb.batterySendBroadcast(intent);
+                    }
+                    break;
             }
         }
     }
@@ -182,22 +199,20 @@
     // elapsed time by the number of active timers to arrive at that timer's share of the time.
     // In order to do this, we must refresh each timer whenever the number of active timers
     // changes.
-    final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<StopwatchTimer>();
-    final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<StopwatchTimer>();
-    final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<StopwatchTimer>();
-    final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers
-            = new SparseArray<ArrayList<StopwatchTimer>>();
-    final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<StopwatchTimer>();
-    final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<StopwatchTimer>();
-    final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<StopwatchTimer>();
-    final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<StopwatchTimer>();
-    final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers =
-            new SparseArray<ArrayList<StopwatchTimer>>();
-    final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<StopwatchTimer>();
-    final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mPartialTimers = new ArrayList<>();
+    final ArrayList<StopwatchTimer> mFullTimers = new ArrayList<>();
+    final ArrayList<StopwatchTimer> mWindowTimers = new ArrayList<>();
+    final SparseArray<ArrayList<StopwatchTimer>> mSensorTimers = new SparseArray<>();
+    final ArrayList<StopwatchTimer> mWifiRunningTimers = new ArrayList<>();
+    final ArrayList<StopwatchTimer> mFullWifiLockTimers = new ArrayList<>();
+    final ArrayList<StopwatchTimer> mWifiMulticastTimers = new ArrayList<>();
+    final ArrayList<StopwatchTimer> mWifiScanTimers = new ArrayList<>();
+    final SparseArray<ArrayList<StopwatchTimer>> mWifiBatchedScanTimers = new SparseArray<>();
+    final ArrayList<StopwatchTimer> mAudioTurnedOnTimers = new ArrayList<>();
+    final ArrayList<StopwatchTimer> mVideoTurnedOnTimers = new ArrayList<>();
 
     // Last partial timers we use for distributing CPU usage.
-    final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<StopwatchTimer>();
+    final ArrayList<StopwatchTimer> mLastPartialTimers = new ArrayList<>();
 
     // These are the objects that will want to do something when the device
     // is unplugged from power.
@@ -227,7 +242,7 @@
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
     final HistoryItem mHistoryReadTmp = new HistoryItem();
     final HistoryItem mHistoryAddTmp = new HistoryItem();
-    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap();
+    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<>();
     String[] mReadHistoryStrings;
     int[] mReadHistoryUids;
     int mReadHistoryChars;
@@ -393,6 +408,12 @@
     boolean mOnBattery;
     boolean mOnBatteryInternal;
 
+    /**
+     * External reporting of whether the device is actually charging.
+     */
+    boolean mCharging = true;
+    int mLastChargingStateLevel;
+
     /*
      * These keep track of battery levels (1-100) at the last plug event and the last unplug event.
      */
@@ -450,6 +471,10 @@
 
     private final NetworkStats.Entry mTmpNetworkStatsEntry = new NetworkStats.Entry();
 
+    private PowerProfile mPowerProfile;
+    private boolean mHasWifiEnergyReporting = false;
+    private boolean mHasBluetoothEnergyReporting = false;
+
     /*
      * Holds a SamplingTimer associated with each kernel wakelock name being tracked.
      */
@@ -928,6 +953,12 @@
         long mUnpluggedTime;
 
         /**
+         * The total time this timer has been running until the latest mark has been set.
+         * Subtract this from mTotalTime to get the time spent running since the mark was set.
+         */
+        long mTimeBeforeMark;
+
+        /**
          * Constructs from a parcel.
          * @param type
          * @param timeBase
@@ -945,6 +976,7 @@
             mLoadedTime = in.readLong();
             mLastTime = 0;
             mUnpluggedTime = in.readLong();
+            mTimeBeforeMark = in.readLong();
             timeBase.add(this);
             if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime);
         }
@@ -964,7 +996,7 @@
          * so can be completely dropped.
          */
         boolean reset(boolean detachIfReset) {
-            mTotalTime = mLoadedTime = mLastTime = 0;
+            mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0;
             mCount = mLoadedCount = mLastCount = 0;
             if (detachIfReset) {
                 detach();
@@ -985,8 +1017,10 @@
             out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)));
             out.writeLong(mLoadedTime);
             out.writeLong(mUnpluggedTime);
+            out.writeLong(mTimeBeforeMark);
         }
 
+        @Override
         public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) {
             if (DEBUG && mType < 0) {
                 Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime
@@ -1002,6 +1036,7 @@
             }
         }
 
+        @Override
         public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             if (DEBUG && mType < 0) {
                 Log.v(TAG, "plug #" + mType + ": realtime=" + baseRealtime
@@ -1055,6 +1090,13 @@
             return val;
         }
 
+        @Override
+        public long getTimeSinceMarkLocked(long elapsedRealtimeUs) {
+            long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs));
+            return val - mTimeBeforeMark;
+        }
+
+        @Override
         public void logState(Printer pw, String prefix) {
             pw.println(prefix + "mCount=" + mCount
                     + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
@@ -1080,6 +1122,9 @@
             mCount = mLoadedCount = in.readInt();
             mLastCount = 0;
             mUnpluggedCount = mCount;
+
+            // When reading the summary, we set the mark to be the latest information.
+            mTimeBeforeMark = mTotalTime;
         }
     }
 
@@ -1475,21 +1520,6 @@
             return mNesting > 0;
         }
 
-        long checkpointRunningLocked(long elapsedRealtimeMs) {
-            if (mNesting > 0) {
-                // We are running...
-                final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
-                if (mTimerPool != null) {
-                    return refreshTimersLocked(batteryRealtime, mTimerPool, this);
-                }
-                final long heldTime = batteryRealtime - mUpdateTime;
-                mUpdateTime = batteryRealtime;
-                mTotalTime += heldTime;
-                return heldTime;
-            }
-            return 0;
-        }
-
         void stopRunningLocked(long elapsedRealtimeMs) {
             // Ignore attempt to stop a timer that isn't running
             if (mNesting == 0) {
@@ -1567,6 +1597,7 @@
             return mCount;
         }
 
+        @Override
         boolean reset(boolean detachIfReset) {
             boolean canDetach = mNesting <= 0;
             super.reset(canDetach && detachIfReset);
@@ -1577,6 +1608,7 @@
             return canDetach;
         }
 
+        @Override
         void detach() {
             super.detach();
             if (mTimerPool != null) {
@@ -1584,10 +1616,31 @@
             }
         }
 
+        @Override
         void readSummaryFromParcelLocked(Parcel in) {
             super.readSummaryFromParcelLocked(in);
             mNesting = 0;
         }
+
+        /**
+         * Set the mark so that we can query later for the total time the timer has
+         * accumulated since this point. The timer can be running or not.
+         *
+         * @param elapsedRealtimeMs the current elapsed realtime in milliseconds.
+         */
+        public void setMark(long elapsedRealtimeMs) {
+            final long batteryRealtime = mTimeBase.getRealtime(elapsedRealtimeMs * 1000);
+            if (mNesting > 0) {
+                // We are running.
+                if (mTimerPool != null) {
+                    refreshTimersLocked(batteryRealtime, mTimerPool, this);
+                } else {
+                    mTotalTime += batteryRealtime - mUpdateTime;
+                    mUpdateTime = batteryRealtime;
+                }
+            }
+            mTimeBeforeMark = mTotalTime;
+        }
     }
 
     public abstract class OverflowArrayMap<T> {
@@ -3890,7 +3943,6 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock on to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
-            scheduleSyncExternalStatsLocked();
         }
         mWifiFullLockNesting++;
         getUidStatsLocked(uid).noteFullWifiLockAcquiredLocked(elapsedRealtime);
@@ -3906,7 +3958,6 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI full lock off to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
-            scheduleSyncExternalStatsLocked();
         }
         getUidStatsLocked(uid).noteFullWifiLockReleasedLocked(elapsedRealtime);
     }
@@ -3964,7 +4015,6 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast on to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
-            scheduleSyncExternalStatsLocked();
         }
         mWifiMulticastNesting++;
         getUidStatsLocked(uid).noteWifiMulticastEnabledLocked(elapsedRealtime);
@@ -3980,7 +4030,6 @@
             if (DEBUG_HISTORY) Slog.v(TAG, "WIFI multicast off to: "
                     + Integer.toHexString(mHistoryCur.states));
             addHistoryRecordLocked(elapsedRealtime, uptime);
-            scheduleSyncExternalStatsLocked();
         }
         getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(elapsedRealtime);
     }
@@ -4088,7 +4137,8 @@
         // During device boot, qtaguid isn't enabled until after the inital
         // loading of battery stats. Now that they're enabled, take our initial
         // snapshot for future delta calculation.
-        updateMobileRadioStateLocked(SystemClock.elapsedRealtime());
+        final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+        updateMobileRadioStateLocked(elapsedRealtimeMs);
         updateWifiStateLocked(null);
     }
 
@@ -4250,6 +4300,10 @@
         return mBluetoothStateTimer[bluetoothState].getCountLocked(which);
     }
 
+    @Override public boolean hasBluetoothActivityReporting() {
+        return mHasBluetoothEnergyReporting;
+    }
+
     @Override public long getBluetoothControllerActivity(int type, int which) {
         if (type >= 0 && type < mBluetoothActivityCounters.length) {
             return mBluetoothActivityCounters[type].getCountLocked(which);
@@ -4257,6 +4311,10 @@
         return 0;
     }
 
+    @Override public boolean hasWifiActivityReporting() {
+        return mHasWifiEnergyReporting;
+    }
+
     @Override public long getWifiControllerActivity(int type, int which) {
         if (type >= 0 && type < mWifiActivityCounters.length) {
             return mWifiActivityCounters[type].getCountLocked(which);
@@ -4369,6 +4427,18 @@
         LongSamplingCounter mMobileRadioActiveCount;
 
         /**
+         * The amount of time this uid has kept the WiFi controller in idle, tx, and rx mode.
+         */
+        LongSamplingCounter[] mWifiControllerTime =
+                new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+
+        /**
+         * The amount of time this uid has kept the Bluetooth controller in idle, tx, and rx mode.
+         */
+        LongSamplingCounter[] mBluetoothControllerTime =
+                new LongSamplingCounter[NUM_CONTROLLER_ACTIVITY_TYPES];
+
+        /**
          * The CPU times we had at the last history details update.
          */
         long mLastStepUserTime;
@@ -4404,22 +4474,22 @@
         /**
          * The statistics we have collected for this uid's sensor activations.
          */
-        final SparseArray<Sensor> mSensorStats = new SparseArray<Sensor>();
+        final SparseArray<Sensor> mSensorStats = new SparseArray<>();
 
         /**
          * The statistics we have collected for this uid's processes.
          */
-        final ArrayMap<String, Proc> mProcessStats = new ArrayMap<String, Proc>();
+        final ArrayMap<String, Proc> mProcessStats = new ArrayMap<>();
 
         /**
          * The statistics we have collected for this uid's processes.
          */
-        final ArrayMap<String, Pkg> mPackageStats = new ArrayMap<String, Pkg>();
+        final ArrayMap<String, Pkg> mPackageStats = new ArrayMap<>();
 
         /**
          * The transient wake stats we have collected for this uid's pids.
          */
-        final SparseArray<Pid> mPids = new SparseArray<Pid>();
+        final SparseArray<Pid> mPids = new SparseArray<>();
 
         public Uid(int uid) {
             mUid = uid;
@@ -4580,6 +4650,13 @@
             }
         }
 
+        public void noteWifiControllerActivityLocked(int type, long timeMs) {
+            if (mWifiControllerTime[type] == null) {
+                mWifiControllerTime[type] = new LongSamplingCounter(mOnBatteryTimeBase);
+            }
+            mWifiControllerTime[type].addCountLocked(timeMs);
+        }
+
         public StopwatchTimer createAudioTurnedOnTimerLocked() {
             if (mAudioTurnedOnTimer == null) {
                 mAudioTurnedOnTimer = new StopwatchTimer(Uid.this, AUDIO_TURNED_ON,
@@ -4895,6 +4972,15 @@
                     ? (int)mMobileRadioActiveCount.getCountLocked(which) : 0;
         }
 
+        @Override
+        public long getWifiControllerActivity(int type, int which) {
+            if (type >= 0 && type < NUM_CONTROLLER_ACTIVITY_TYPES &&
+                    mWifiControllerTime[type] != null) {
+                return mWifiControllerTime[type].getCountLocked(which);
+            }
+            return 0;
+        }
+
         void initNetworkActivityLocked() {
             mNetworkByteActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
             mNetworkPacketActivityCounters = new LongSamplingCounter[NUM_NETWORK_ACTIVITY_TYPES];
@@ -4978,6 +5064,16 @@
                 mMobileRadioActiveCount.reset(false);
             }
 
+            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+                if (mWifiControllerTime[i] != null) {
+                    mWifiControllerTime[i].reset(false);
+                }
+
+                if (mBluetoothControllerTime[i] != null) {
+                    mBluetoothControllerTime[i].reset(false);
+                }
+            }
+
             final ArrayMap<String, Wakelock> wakeStats = mWakelockStats.getMap();
             for (int iw=wakeStats.size()-1; iw>=0; iw--) {
                 Wakelock wl = wakeStats.valueAt(iw);
@@ -5100,6 +5196,16 @@
                         mNetworkPacketActivityCounters[i].detach();
                     }
                 }
+
+                for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+                    if (mWifiControllerTime[i] != null) {
+                        mWifiControllerTime[i].detach();
+                    }
+
+                    if (mBluetoothControllerTime[i] != null) {
+                        mBluetoothControllerTime[i].detach();
+                    }
+                }
                 mPids.clear();
             }
 
@@ -5189,6 +5295,7 @@
             } else {
                 out.writeInt(0);
             }
+
             if (mAudioTurnedOnTimer != null) {
                 out.writeInt(1);
                 mAudioTurnedOnTimer.writeToParcel(out, elapsedRealtimeUs);
@@ -5240,6 +5347,24 @@
             } else {
                 out.writeInt(0);
             }
+
+            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+                if (mWifiControllerTime[i] != null) {
+                    out.writeInt(1);
+                    mWifiControllerTime[i].writeToParcel(out);
+                } else {
+                    out.writeInt(0);
+                }
+            }
+
+            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+                if (mBluetoothControllerTime[i] != null) {
+                    out.writeInt(1);
+                    mBluetoothControllerTime[i].writeToParcel(out);
+                } else {
+                    out.writeInt(0);
+                }
+            }
         }
 
         void readFromParcelLocked(TimeBase timeBase, TimeBase screenOffTimeBase, Parcel in) {
@@ -5389,6 +5514,22 @@
                 mNetworkByteActivityCounters = null;
                 mNetworkPacketActivityCounters = null;
             }
+
+            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+                if (in.readInt() != 0) {
+                    mWifiControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                } else {
+                    mWifiControllerTime[i] = null;
+                }
+            }
+
+            for (int i = 0; i < NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
+                if (in.readInt() != 0) {
+                    mBluetoothControllerTime[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
+                } else {
+                    mBluetoothControllerTime[i] = null;
+                }
+            }
         }
 
         /**
@@ -6644,6 +6785,12 @@
         readFromParcel(p);
     }
 
+    public void setPowerProfile(PowerProfile profile) {
+        synchronized (this) {
+            mPowerProfile = profile;
+        }
+    }
+
     public void setCallback(BatteryCallback cb) {
         mCallback = cb;
     }
@@ -7127,6 +7274,10 @@
         return mOnBattery;
     }
 
+    public boolean isCharging() {
+        return mCharging;
+    }
+
     public boolean isScreenOn() {
         return mScreenState == Display.STATE_ON;
     }
@@ -7367,9 +7518,12 @@
      * @param info The energy information from the WiFi controller.
      */
     public void updateWifiStateLocked(@Nullable final WifiActivityEnergyInfo info) {
-        final NetworkStats delta;
+        final long elapsedRealtimeMs = SystemClock.elapsedRealtime();
+        NetworkStats delta = null;
         try {
-            delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats);
+            if (!ArrayUtils.isEmpty(mWifiIfaces)) {
+                delta = getNetworkStatsDeltaLocked(mWifiIfaces, mWifiNetworkStats);
+            }
         } catch (IOException e) {
             Slog.wtf(TAG, "Failed to get wifi network stats", e);
             return;
@@ -7379,14 +7533,19 @@
             return;
         }
 
+        SparseLongArray rxPackets = new SparseLongArray();
+        SparseLongArray txPackets = new SparseLongArray();
+        long totalTxPackets = 0;
+        long totalRxPackets = 0;
         if (delta != null) {
             final int size = delta.size();
             for (int i = 0; i < size; i++) {
                 final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
 
-                if (DEBUG) {
+                if (DEBUG_ENERGY) {
                     Slog.d(TAG, "Wifi uid " + entry.uid + ": delta rx=" + entry.rxBytes
-                            + " tx=" + entry.txBytes);
+                            + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
+                            + " txPackets=" + entry.txPackets);
                 }
 
                 if (entry.rxBytes == 0 || entry.txBytes == 0) {
@@ -7398,6 +7557,13 @@
                         entry.rxPackets);
                 u.noteNetworkActivityLocked(NETWORK_WIFI_TX_DATA, entry.txBytes,
                         entry.txPackets);
+                rxPackets.put(u.getUid(), entry.rxPackets);
+                txPackets.put(u.getUid(), entry.txPackets);
+
+                // Sum the total number of packets so that the Rx Power and Tx Power can
+                // be evenly distributed amongst the apps.
+                totalRxPackets += entry.rxPackets;
+                totalTxPackets += entry.txPackets;
 
                 mNetworkByteActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
                         entry.rxBytes);
@@ -7411,6 +7577,121 @@
         }
 
         if (info != null) {
+            mHasWifiEnergyReporting = true;
+
+            // Measured in mAms
+            final long txTimeMs = info.getControllerTxTimeMillis();
+            final long rxTimeMs = info.getControllerRxTimeMillis();
+            final long idleTimeMs = info.getControllerIdleTimeMillis();
+            final long totalTimeMs = txTimeMs + rxTimeMs + idleTimeMs;
+
+            long leftOverRxTimeMs = rxTimeMs;
+
+            if (DEBUG_ENERGY) {
+                Slog.d(TAG, "------ BEGIN WiFi power blaming ------");
+                Slog.d(TAG, "  Tx Time:    " + txTimeMs + " ms");
+                Slog.d(TAG, "  Rx Time:    " + rxTimeMs + " ms");
+                Slog.d(TAG, "  Idle Time:  " + idleTimeMs + " ms");
+                Slog.d(TAG, "  Total Time: " + totalTimeMs + " ms");
+            }
+
+            long totalWifiLockTimeMs = 0;
+            long totalScanTimeMs = 0;
+
+            // On the first pass, collect some totals so that we can normalize power
+            // calculations if we need to.
+            final int uidStatsSize = mUidStats.size();
+            for (int i = 0; i < uidStatsSize; i++) {
+                final Uid uid = mUidStats.valueAt(i);
+
+                // Sum the total scan power for all apps.
+                totalScanTimeMs += uid.mWifiScanTimer.getTimeSinceMarkLocked(
+                        elapsedRealtimeMs * 1000) / 1000;
+
+                // Sum the total time holding wifi lock for all apps.
+                totalWifiLockTimeMs += uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
+                        elapsedRealtimeMs * 1000) / 1000;
+            }
+
+            if (DEBUG_ENERGY && totalScanTimeMs > rxTimeMs) {
+                Slog.d(TAG, "  !Estimated scan time > Actual rx time (" + totalScanTimeMs + " ms > "
+                        + rxTimeMs + " ms). Normalizing scan time.");
+            }
+
+            // Actually assign and distribute power usage to apps.
+            for (int i = 0; i < uidStatsSize; i++) {
+                final Uid uid = mUidStats.valueAt(i);
+
+                long scanTimeSinceMarkMs = uid.mWifiScanTimer.getTimeSinceMarkLocked(
+                        elapsedRealtimeMs * 1000) / 1000;
+                if (scanTimeSinceMarkMs > 0) {
+                    // Set the new mark so that next time we get new data since this point.
+                    uid.mWifiScanTimer.setMark(elapsedRealtimeMs);
+
+                    if (totalScanTimeMs > rxTimeMs) {
+                        // Our total scan time is more than the reported Rx time.
+                        // This is possible because the cost of a scan is approximate.
+                        // Let's normalize the result so that we evenly blame each app
+                        // scanning.
+                        //
+                        // This means that we may have apps that received packets not be blamed
+                        // for this, but this is fine as scans are relatively more expensive.
+                        scanTimeSinceMarkMs = (rxTimeMs * scanTimeSinceMarkMs) / totalScanTimeMs;
+                    }
+
+                    if (DEBUG_ENERGY) {
+                        Slog.d(TAG, "  ScanTime for UID " + uid.getUid() + ": "
+                                + scanTimeSinceMarkMs + " ms)");
+                    }
+                    uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, scanTimeSinceMarkMs);
+                    leftOverRxTimeMs -= scanTimeSinceMarkMs;
+                }
+
+                // Distribute evenly the power consumed while Idle to each app holding a WiFi
+                // lock.
+                final long wifiLockTimeSinceMarkMs = uid.mFullWifiLockTimer.getTimeSinceMarkLocked(
+                        elapsedRealtimeMs * 1000) / 1000;
+                if (wifiLockTimeSinceMarkMs > 0) {
+                    // Set the new mark so that next time we get new data since this point.
+                    uid.mFullWifiLockTimer.setMark(elapsedRealtimeMs);
+
+                    final long myIdleTimeMs = (wifiLockTimeSinceMarkMs * idleTimeMs)
+                            / totalWifiLockTimeMs;
+                    if (DEBUG_ENERGY) {
+                        Slog.d(TAG, "  IdleTime for UID " + uid.getUid() + ": "
+                                + myIdleTimeMs + " ms");
+                    }
+                    uid.noteWifiControllerActivityLocked(CONTROLLER_IDLE_TIME, myIdleTimeMs);
+                }
+            }
+
+            if (DEBUG_ENERGY) {
+                Slog.d(TAG, "  New RxPower: " + leftOverRxTimeMs + " ms");
+            }
+
+            // Distribute the Tx power appropriately between all apps that transmitted packets.
+            for (int i = 0; i < txPackets.size(); i++) {
+                final Uid uid = getUidStatsLocked(txPackets.keyAt(i));
+                final long myTxTimeMs = (txPackets.valueAt(i) * txTimeMs) / totalTxPackets;
+                if (DEBUG_ENERGY) {
+                    Slog.d(TAG, "  TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
+                }
+                uid.noteWifiControllerActivityLocked(CONTROLLER_TX_TIME, myTxTimeMs);
+            }
+
+            // Distribute the remaining Rx power appropriately between all apps that received
+            // packets.
+            for (int i = 0; i < rxPackets.size(); i++) {
+                final Uid uid = getUidStatsLocked(rxPackets.keyAt(i));
+                final long myRxTimeMs = (rxPackets.valueAt(i) * leftOverRxTimeMs) / totalRxPackets;
+                if (DEBUG_ENERGY) {
+                    Slog.d(TAG, "  RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
+                }
+                uid.noteWifiControllerActivityLocked(CONTROLLER_RX_TIME, myRxTimeMs);
+            }
+
+            // Any left over power use will be picked up by the WiFi category in BatteryStatsHelper.
+
             // Update WiFi controller stats.
             mWifiActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
                     info.getControllerRxTimeMillis());
@@ -7418,19 +7699,29 @@
                     info.getControllerTxTimeMillis());
             mWifiActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
                     info.getControllerIdleTimeMillis());
-            mWifiActivityCounters[CONTROLLER_ENERGY].addCountLocked(
-                    info.getControllerEnergyUsed());
+
+            final double powerDrainMaMs;
+            if (mPowerProfile.getAveragePower(
+                    PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) == 0) {
+                powerDrainMaMs = 0.0;
+            } else {
+                powerDrainMaMs = info.getControllerEnergyUsed()
+                        / mPowerProfile.getAveragePower(
+                        PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE);
+            }
+            mWifiActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked((long) powerDrainMaMs);
         }
     }
 
     /**
      * Distribute Cell radio energy info and network traffic to apps.
      */
-    public void updateMobileRadioStateLocked(long elapsedRealtimeMs) {
-        final NetworkStats delta;
-
+    public void updateMobileRadioStateLocked(final long elapsedRealtimeMs) {
+        NetworkStats delta = null;
         try {
-            delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
+            if (!ArrayUtils.isEmpty(mMobileIfaces)) {
+                delta = getNetworkStatsDeltaLocked(mMobileIfaces, mMobileNetworkStats);
+            }
         } catch (IOException e) {
             Slog.wtf(TAG, "Failed to get mobile network stats", e);
             return;
@@ -7440,14 +7731,24 @@
             return;
         }
 
-        long radioTime = mMobileRadioActivePerAppTimer.checkpointRunningLocked(elapsedRealtimeMs);
+        long radioTime = mMobileRadioActivePerAppTimer.getTimeSinceMarkLocked(
+                elapsedRealtimeMs * 1000);
+        mMobileRadioActivePerAppTimer.setMark(elapsedRealtimeMs);
         long totalPackets = delta.getTotalPackets();
 
         final int size = delta.size();
         for (int i = 0; i < size; i++) {
             final NetworkStats.Entry entry = delta.getValues(i, mTmpNetworkStatsEntry);
 
-            if (entry.rxBytes == 0 || entry.txBytes == 0) continue;
+            if (entry.rxBytes == 0 || entry.txBytes == 0) {
+                continue;
+            }
+
+            if (DEBUG_ENERGY) {
+                Slog.d(TAG, "Mobile uid " + entry.uid + ": delta rx=" + entry.rxBytes
+                        + " tx=" + entry.txBytes + " rxPackets=" + entry.rxPackets
+                        + " txPackets=" + entry.txPackets);
+            }
 
             final Uid u = getUidStatsLocked(mapUid(entry.uid));
             u.noteNetworkActivityLocked(NETWORK_MOBILE_RX_DATA, entry.rxBytes,
@@ -7488,14 +7789,15 @@
      * @param info The energy information from the bluetooth controller.
      */
     public void updateBluetoothStateLocked(@Nullable final BluetoothActivityEnergyInfo info) {
-        if (info != null && mOnBatteryInternal) {
+        if (info != null && mOnBatteryInternal && false) {
+            mHasBluetoothEnergyReporting = true;
             mBluetoothActivityCounters[CONTROLLER_RX_TIME].addCountLocked(
                     info.getControllerRxTimeMillis());
             mBluetoothActivityCounters[CONTROLLER_TX_TIME].addCountLocked(
                     info.getControllerTxTimeMillis());
             mBluetoothActivityCounters[CONTROLLER_IDLE_TIME].addCountLocked(
                     info.getControllerIdleTimeMillis());
-            mBluetoothActivityCounters[CONTROLLER_ENERGY].addCountLocked(
+            mBluetoothActivityCounters[CONTROLLER_POWER_DRAIN].addCountLocked(
                     info.getControllerEnergyUsed());
         }
     }
@@ -7538,6 +7840,20 @@
         }
     }
 
+    boolean setChargingLocked(boolean charging) {
+        if (mCharging != charging) {
+            mCharging = charging;
+            if (charging) {
+                mHistoryCur.states |= HistoryItem.STATE_CHARGING_FLAG;
+            } else {
+                mHistoryCur.states &= ~HistoryItem.STATE_CHARGING_FLAG;
+            }
+            mHandler.sendEmptyMessage(MSG_REPORT_CHARGING);
+            return true;
+        }
+        return false;
+    }
+
     void setOnBatteryLocked(final long mSecRealtime, final long mSecUptime, final boolean onBattery,
             final int oldStatus, final int level) {
         boolean doWrite = false;
@@ -7597,6 +7913,10 @@
                 reset = true;
                 mDischargeStepTracker.init();
             }
+            if (mCharging) {
+                setChargingLocked(false);
+            }
+            mLastChargingStateLevel = level;
             mOnBattery = mOnBatteryInternal = true;
             mLastDischargeStepLevel = level;
             mMinDischargeStepLevel = level;
@@ -7626,6 +7946,7 @@
             mDischargeAmountScreenOff = 0;
             updateTimeBasesLocked(true, !screenOn, uptime, realtime);
         } else {
+            mLastChargingStateLevel = level;
             mOnBattery = mOnBatteryInternal = false;
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
@@ -7718,10 +8039,13 @@
                     mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
                 }
             }
+            // Always start out assuming charging, that will be updated later.
+            mHistoryCur.states |= HistoryItem.STATE_CHARGING_FLAG;
             mHistoryCur.batteryStatus = (byte)status;
             mHistoryCur.batteryLevel = (byte)level;
             mMaxChargeStepLevel = mMinDischargeStepLevel =
                     mLastChargeStepLevel = mLastDischargeStepLevel = level;
+            mLastChargingStateLevel = level;
         } else if (mCurrentBatteryLevel != level || mOnBattery != onBattery) {
             recordDailyStatsIfNeededLocked(level >= 100 && onBattery);
         }
@@ -7782,13 +8106,11 @@
                 mHistoryCur.batteryVoltage = (char)volt;
                 changed = true;
             }
-            if (changed) {
-                addHistoryRecordLocked(elapsedRealtime, uptime);
-            }
             long modeBits = (((long)mInitStepMode) << STEP_LEVEL_INITIAL_MODE_SHIFT)
                     | (((long)mModStepMode) << STEP_LEVEL_MODIFIED_MODE_SHIFT)
                     | (((long)(level&0xff)) << STEP_LEVEL_LEVEL_SHIFT);
             if (onBattery) {
+                changed |= setChargingLocked(false);
                 if (mLastDischargeStepLevel != level && mMinDischargeStepLevel > level) {
                     mDischargeStepTracker.addLevelSteps(mLastDischargeStepLevel - level,
                             modeBits, elapsedRealtime);
@@ -7800,6 +8122,28 @@
                     mModStepMode = 0;
                 }
             } else {
+                if (level >= 90) {
+                    // If the battery level is at least 90%, always consider the device to be
+                    // charging even if it happens to go down a level.
+                    changed |= setChargingLocked(true);
+                    mLastChargeStepLevel = level;
+                } if (!mCharging) {
+                    if (mLastChargeStepLevel < level) {
+                        // We have not reporting that we are charging, but the level has now
+                        // gone up, so consider the state to be charging.
+                        changed |= setChargingLocked(true);
+                        mLastChargeStepLevel = level;
+                    }
+                } else {
+                    if (mLastChargeStepLevel > level) {
+                        // We had reported that the device was charging, but here we are with
+                        // power connected and the level going down.  Looks like the current
+                        // power supplied isn't enough, so consider the device to now be
+                        // discharging.
+                        changed |= setChargingLocked(false);
+                        mLastChargeStepLevel = level;
+                    }
+                }
                 if (mLastChargeStepLevel != level && mMaxChargeStepLevel < level) {
                     mChargeStepTracker.addLevelSteps(level - mLastChargeStepLevel,
                             modeBits, elapsedRealtime);
@@ -7811,6 +8155,9 @@
                     mModStepMode = 0;
                 }
             }
+            if (changed) {
+                addHistoryRecordLocked(elapsedRealtime, uptime);
+            }
         }
         if (!onBattery && status == BatteryManager.BATTERY_STATUS_FULL) {
             // We don't record history while we are plugged in and fully charged.
@@ -9199,6 +9546,8 @@
             mWifiActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase, in);
         }
 
+        mHasWifiEnergyReporting = in.readInt() != 0;
+        mHasBluetoothEnergyReporting = in.readInt() != 0;
         mNumConnectivityChange = in.readInt();
         mLoadedNumConnectivityChange = in.readInt();
         mUnpluggedNumConnectivityChange = in.readInt();
@@ -9352,6 +9701,8 @@
         for (int i=0; i< NUM_CONTROLLER_ACTIVITY_TYPES; i++) {
             mWifiActivityCounters[i].writeToParcel(out);
         }
+        out.writeInt(mHasWifiEnergyReporting ? 1 : 0);
+        out.writeInt(mHasBluetoothEnergyReporting ? 1 : 0);
         out.writeInt(mNumConnectivityChange);
         out.writeInt(mLoadedNumConnectivityChange);
         out.writeInt(mUnpluggedNumConnectivityChange);
diff --git a/core/java/com/android/internal/os/BluetoothPowerCalculator.java b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
new file mode 100644
index 0000000..3557209
--- /dev/null
+++ b/core/java/com/android/internal/os/BluetoothPowerCalculator.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.Log;
+
+public class BluetoothPowerCalculator extends PowerCalculator {
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+    private static final String TAG = "BluetoothPowerCalculator";
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+        // No per-app distribution yet.
+    }
+
+    @Override
+    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+                                   long rawUptimeUs, int statsType) {
+        final long idleTimeMs = stats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_IDLE_TIME, statsType);
+        final long txTimeMs = stats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_TX_TIME, statsType);
+        final long rxTimeMs = stats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_RX_TIME, statsType);
+        final long powerMaMs = stats.getBluetoothControllerActivity(
+                BatteryStats.CONTROLLER_POWER_DRAIN, statsType);
+        final double powerMah = powerMaMs / (double)(1000*60*60);
+        final long totalTimeMs = idleTimeMs + txTimeMs + rxTimeMs;
+
+        if (DEBUG && powerMah != 0) {
+            Log.d(TAG, "Bluetooth active: time=" + (totalTimeMs)
+                    + " power=" + BatteryStatsHelper.makemAh(powerMah));
+        }
+
+        app.usagePowerMah = powerMah;
+        app.usageTimeMs = totalTimeMs;
+    }
+}
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
new file mode 100644
index 0000000..6c3f958
--- /dev/null
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.ArrayMap;
+import android.util.Log;
+
+public class CpuPowerCalculator extends PowerCalculator {
+    private static final String TAG = "CpuPowerCalculator";
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+
+    private final double[] mPowerCpuNormal;
+
+    /**
+     * Reusable array for calculations.
+     */
+    private final long[] mSpeedStepTimes;
+
+    public CpuPowerCalculator(PowerProfile profile) {
+        final int speedSteps = profile.getNumSpeedSteps();
+        mPowerCpuNormal = new double[speedSteps];
+        mSpeedStepTimes = new long[speedSteps];
+        for (int p = 0; p < speedSteps; p++) {
+            mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
+        }
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+        final int speedSteps = mSpeedStepTimes.length;
+
+        // Keep track of the package with highest drain.
+        double highestDrain = 0;
+
+        final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
+        final int processStatsCount = processStats.size();
+        for (int i = 0; i < processStatsCount; i++) {
+            final BatteryStats.Uid.Proc ps = processStats.valueAt(i);
+            final String processName = processStats.keyAt(i);
+
+            app.cpuFgTimeMs += ps.getForegroundTime(statsType);
+            final long totalCpuTime = ps.getUserTime(statsType) + ps.getSystemTime(statsType);
+            app.cpuTimeMs += totalCpuTime;
+
+            // Calculate the total CPU time spent at the various speed steps.
+            long totalTimeAtSpeeds = 0;
+            for (int step = 0; step < speedSteps; step++) {
+                mSpeedStepTimes[step] = ps.getTimeAtCpuSpeedStep(step, statsType);
+                totalTimeAtSpeeds += mSpeedStepTimes[step];
+            }
+            totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
+
+            // Then compute the ratio of time spent at each speed and figure out
+            // the total power consumption.
+            double cpuPower = 0;
+            for (int step = 0; step < speedSteps; step++) {
+                final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
+                final double cpuSpeedStepPower = ratio * totalCpuTime * mPowerCpuNormal[step];
+                if (DEBUG && ratio != 0) {
+                    Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
+                            + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
+                            + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
+                }
+                cpuPower += cpuSpeedStepPower;
+            }
+
+            if (DEBUG && cpuPower != 0) {
+                Log.d(TAG, String.format("process %s, cpu power=%s",
+                        processName, BatteryStatsHelper.makemAh(cpuPower / (60 * 60 * 1000))));
+            }
+            app.cpuPowerMah += cpuPower;
+
+            // Each App can have multiple packages and with multiple running processes.
+            // Keep track of the package who's process has the highest drain.
+            if (app.packageWithHighestDrain == null ||
+                    app.packageWithHighestDrain.startsWith("*")) {
+                highestDrain = cpuPower;
+                app.packageWithHighestDrain = processName;
+            } else if (highestDrain < cpuPower && !processName.startsWith("*")) {
+                highestDrain = cpuPower;
+                app.packageWithHighestDrain = processName;
+            }
+        }
+
+        // Ensure that the CPU times make sense.
+        if (app.cpuFgTimeMs > app.cpuTimeMs) {
+            if (DEBUG && app.cpuFgTimeMs > app.cpuTimeMs + 10000) {
+                Log.d(TAG, "WARNING! Cputime is more than 10 seconds behind Foreground time");
+            }
+
+            // Statistics may not have been gathered yet.
+            app.cpuTimeMs = app.cpuFgTimeMs;
+        }
+
+        // Convert the CPU power to mAh
+        app.cpuPowerMah /= (60 * 60 * 1000);
+    }
+}
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index 433a54b..671bf24 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -90,12 +90,15 @@
         }
     }
 
-    public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
-        return dexopt(apkPath, uid, isPublic, "*", instructionSet, false, false);
+    public int dexopt(String apkPath, int uid, boolean isPublic,
+            String instructionSet, int dexoptNeeded) {
+        return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
+                false, false, null);
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, boolean vmSafeMode, boolean debuggable) {
+            String instructionSet, int dexoptNeeded, boolean vmSafeMode,
+            boolean debuggable, String outputPath) {
         StringBuilder builder = new StringBuilder("dexopt");
         builder.append(' ');
         builder.append(apkPath);
@@ -106,27 +109,12 @@
         builder.append(pkgName);
         builder.append(' ');
         builder.append(instructionSet);
+        builder.append(' ');
+        builder.append(dexoptNeeded);
         builder.append(vmSafeMode ? " 1" : " 0");
         builder.append(debuggable ? " 1" : " 0");
-        return execute(builder.toString());
-    }
-
-    public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
-        return patchoat(apkPath, uid, isPublic, "*", instructionSet);
-    }
-
-    public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet) {
-        StringBuilder builder = new StringBuilder("patchoat");
         builder.append(' ');
-        builder.append(apkPath);
-        builder.append(' ');
-        builder.append(uid);
-        builder.append(isPublic ? " 1" : " 0");
-        builder.append(' ');
-        builder.append(pkgName);
-        builder.append(' ');
-        builder.append(instructionSet);
+        builder.append(outputPath != null ? outputPath : "!");
         return execute(builder.toString());
     }
 
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
new file mode 100644
index 0000000..9711c3b
--- /dev/null
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.telephony.SignalStrength;
+import android.util.Log;
+
+public class MobileRadioPowerCalculator extends PowerCalculator {
+    private static final String TAG = "MobileRadioPowerController";
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+    private final double mPowerRadioOn;
+    private final double[] mPowerBins = new double[SignalStrength.NUM_SIGNAL_STRENGTH_BINS];
+    private final double mPowerScan;
+    private BatteryStats mStats;
+    private long mTotalAppMobileActiveMs = 0;
+
+    /**
+     * Return estimated power (in mAs) of sending or receiving a packet with the mobile radio.
+     */
+    private double getMobilePowerPerPacket(long rawRealtimeUs, int statsType) {
+        final long MOBILE_BPS = 200000; // TODO: Extract average bit rates from system
+        final double MOBILE_POWER = mPowerRadioOn / 3600;
+
+        final long mobileRx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
+                statsType);
+        final long mobileTx = mStats.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
+                statsType);
+        final long mobileData = mobileRx + mobileTx;
+
+        final long radioDataUptimeMs =
+                mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
+        final double mobilePps = (mobileData != 0 && radioDataUptimeMs != 0)
+                ? (mobileData / (double)radioDataUptimeMs)
+                : (((double)MOBILE_BPS) / 8 / 2048);
+        return (MOBILE_POWER / mobilePps) / (60*60);
+    }
+
+    public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) {
+        mPowerRadioOn = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE);
+        for (int i = 0; i < mPowerBins.length; i++) {
+            mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE, i);
+        }
+        mPowerScan = profile.getAveragePower(PowerProfile.POWER_RADIO_SCANNING);
+        mStats = stats;
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+        // Add cost of mobile traffic.
+        app.mobileRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_RX_DATA,
+                statsType);
+        app.mobileTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_MOBILE_TX_DATA,
+                statsType);
+        app.mobileActive = u.getMobileRadioActiveTime(statsType) / 1000;
+        app.mobileActiveCount = u.getMobileRadioActiveCount(statsType);
+        app.mobileRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_RX_DATA,
+                statsType);
+        app.mobileTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_MOBILE_TX_DATA,
+                statsType);
+
+        if (app.mobileActive > 0) {
+            // We are tracking when the radio is up, so can use the active time to
+            // determine power use.
+            mTotalAppMobileActiveMs += app.mobileActive;
+            app.mobileRadioPowerMah = (app.mobileActive * mPowerRadioOn) / (1000*60*60);
+        } else {
+            // We are not tracking when the radio is up, so must approximate power use
+            // based on the number of packets.
+            app.mobileRadioPowerMah = (app.mobileRxPackets + app.mobileTxPackets)
+                    * getMobilePowerPerPacket(rawRealtimeUs, statsType);
+        }
+        if (DEBUG && app.mobileRadioPowerMah != 0) {
+            Log.d(TAG, "UID " + u.getUid() + ": mobile packets "
+                    + (app.mobileRxPackets + app.mobileTxPackets)
+                    + " active time " + app.mobileActive
+                    + " power=" + BatteryStatsHelper.makemAh(app.mobileRadioPowerMah));
+        }
+    }
+
+    @Override
+    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+                                   long rawUptimeUs, int statsType) {
+        double power = 0;
+        long signalTimeMs = 0;
+        long noCoverageTimeMs = 0;
+        for (int i = 0; i < mPowerBins.length; i++) {
+            long strengthTimeMs = stats.getPhoneSignalStrengthTime(i, rawRealtimeUs, statsType)
+                    / 1000;
+            final double p = (strengthTimeMs * mPowerBins[i]) / (60*60*1000);
+            if (DEBUG && p != 0) {
+                Log.d(TAG, "Cell strength #" + i + ": time=" + strengthTimeMs + " power="
+                        + BatteryStatsHelper.makemAh(p));
+            }
+            power += p;
+            signalTimeMs += strengthTimeMs;
+            if (i == 0) {
+                noCoverageTimeMs = strengthTimeMs;
+            }
+        }
+
+        final long scanningTimeMs = stats.getPhoneSignalScanningTime(rawRealtimeUs, statsType)
+                / 1000;
+        final double p = (scanningTimeMs * mPowerScan) / (60*60*1000);
+        if (DEBUG && p != 0) {
+            Log.d(TAG, "Cell radio scanning: time=" + scanningTimeMs
+                    + " power=" + BatteryStatsHelper.makemAh(p));
+        }
+        power += p;
+        long radioActiveTimeMs = mStats.getMobileRadioActiveTime(rawRealtimeUs, statsType) / 1000;
+        long remainingActiveTimeMs = radioActiveTimeMs - mTotalAppMobileActiveMs;
+        if (remainingActiveTimeMs > 0) {
+            power += (mPowerRadioOn * remainingActiveTimeMs) / (1000*60*60);
+        }
+
+        if (power != 0) {
+            app.noCoveragePercent = noCoverageTimeMs * 100.0 / signalTimeMs;
+            app.mobileActive = remainingActiveTimeMs;
+            app.mobileActiveCount = stats.getMobileRadioActiveUnknownCount(statsType);
+            app.mobileRadioPowerMah = power;
+        }
+    }
+
+    @Override
+    public void reset() {
+        mTotalAppMobileActiveMs = 0;
+    }
+
+    public void reset(BatteryStats stats) {
+        reset();
+        mStats = stats;
+    }
+}
diff --git a/core/java/com/android/internal/os/PowerCalculator.java b/core/java/com/android/internal/os/PowerCalculator.java
new file mode 100644
index 0000000..cd69d68
--- /dev/null
+++ b/core/java/com/android/internal/os/PowerCalculator.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+
+/**
+ * Calculates power use of a device subsystem for an app.
+ */
+public abstract class PowerCalculator {
+    /**
+     * Calculate the amount of power an app used for this subsystem.
+     * @param app The BatterySipper that represents the power use of an app.
+     * @param u The recorded stats for the app.
+     * @param rawRealtimeUs The raw system realtime in microseconds.
+     * @param rawUptimeUs The raw system uptime in microseconds.
+     * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT},
+     *                  {@link BatteryStats#STATS_SINCE_CHARGED}, or
+     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED}.
+     */
+    public abstract void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                                      long rawUptimeUs, int statsType);
+
+    /**
+     * Calculate the remaining power that can not be attributed to an app.
+     * @param app The BatterySipper that will represent this remaining power.
+     * @param stats The BatteryStats object from which to retrieve data.
+     * @param rawRealtimeUs The raw system realtime in microseconds.
+     * @param rawUptimeUs The raw system uptime in microseconds.
+     * @param statsType The type of stats. Can be {@link BatteryStats#STATS_CURRENT},
+     *                  {@link BatteryStats#STATS_SINCE_CHARGED}, or
+     *                  {@link BatteryStats#STATS_SINCE_UNPLUGGED}.
+     */
+    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+                                   long rawUptimeUs, int statsType) {
+    }
+
+    /**
+     * Reset any state maintained in this calculator.
+     */
+    public void reset() {
+    }
+}
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 944eb5a..7e6706c 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -18,6 +18,7 @@
 
 
 import android.content.Context;
+import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 
 import com.android.internal.util.XmlUtils;
@@ -75,10 +76,21 @@
      */
     public static final String POWER_WIFI_ACTIVE = "wifi.active";
 
-    /**
-     * Operating voltage of the WiFi controller.
-     */
-    public static final String OPERATING_VOLTAGE_WIFI = "wifi.voltage";
+    //
+    // Updated power constants. These are not estimated, they are real world
+    // currents and voltages for the underlying bluetooth and wifi controllers.
+    //
+
+    public static final String POWER_WIFI_CONTROLLER_IDLE = "wifi.controller.idle";
+    public static final String POWER_WIFI_CONTROLLER_RX = "wifi.controller.rx";
+    public static final String POWER_WIFI_CONTROLLER_TX = "wifi.controller.tx";
+    public static final String POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE = "wifi.controller.voltage";
+
+    public static final String POWER_BLUETOOTH_CONTROLLER_IDLE = "bluetooth.controller.idle";
+    public static final String POWER_BLUETOOTH_CONTROLLER_RX = "bluetooth.controller.rx";
+    public static final String POWER_BLUETOOTH_CONTROLLER_TX = "bluetooth.controller.tx";
+    public static final String POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE =
+            "bluetooth.controller.voltage";
 
     /**
      * Power consumption when GPS is on.
@@ -100,10 +112,6 @@
      */
     public static final String POWER_BLUETOOTH_AT_CMD = "bluetooth.at";
 
-    /**
-     * Operating voltage of the Bluetooth controller.
-     */
-    public static final String OPERATING_VOLTAGE_BLUETOOTH = "bluetooth.voltage";
 
     /**
      * Power consumption when screen is on, not including the backlight power.
@@ -162,7 +170,7 @@
      */
     public static final String POWER_BATTERY_CAPACITY = "battery.capacity";
 
-    static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
+    static final HashMap<String, Object> sPowerMap = new HashMap<>();
 
     private static final String TAG_DEVICE = "device";
     private static final String TAG_ITEM = "item";
@@ -180,7 +188,8 @@
 
     private void readPowerValuesFromXml(Context context) {
         int id = com.android.internal.R.xml.power_profile;
-        XmlResourceParser parser = context.getResources().getXml(id);
+        final Resources resources = context.getResources();
+        XmlResourceParser parser = resources.getXml(id);
         boolean parsingArray = false;
         ArrayList<Double> array = new ArrayList<Double>();
         String arrayName = null;
@@ -231,6 +240,36 @@
         } finally {
             parser.close();
         }
+
+        // Now collect other config variables.
+        int[] configResIds = new int[] {
+                com.android.internal.R.integer.config_bluetooth_idle_cur_ma,
+                com.android.internal.R.integer.config_bluetooth_rx_cur_ma,
+                com.android.internal.R.integer.config_bluetooth_tx_cur_ma,
+                com.android.internal.R.integer.config_bluetooth_operating_voltage_mv,
+                com.android.internal.R.integer.config_wifi_idle_receive_cur_ma,
+                com.android.internal.R.integer.config_wifi_active_rx_cur_ma,
+                com.android.internal.R.integer.config_wifi_tx_cur_ma,
+                com.android.internal.R.integer.config_wifi_operating_voltage_mv,
+        };
+
+        String[] configResIdKeys = new String[] {
+                POWER_BLUETOOTH_CONTROLLER_IDLE,
+                POWER_BLUETOOTH_CONTROLLER_RX,
+                POWER_BLUETOOTH_CONTROLLER_TX,
+                POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE,
+                POWER_WIFI_CONTROLLER_IDLE,
+                POWER_WIFI_CONTROLLER_RX,
+                POWER_WIFI_CONTROLLER_TX,
+                POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE,
+        };
+
+        for (int i = 0; i < configResIds.length; i++) {
+            int value = resources.getInteger(configResIds[i]);
+            if (value > 0) {
+                sPowerMap.put(configResIdKeys[i], (double) value);
+            }
+        }
     }
 
     /**
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
new file mode 100644
index 0000000..c98639b
--- /dev/null
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.os.BatteryStats;
+import android.util.SparseArray;
+
+import java.util.List;
+
+public class SensorPowerCalculator extends PowerCalculator {
+    private final List<Sensor> mSensors;
+    private final double mGpsPowerOn;
+
+    public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) {
+        mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
+        mGpsPowerOn = profile.getAveragePower(PowerProfile.POWER_GPS_ON);
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+        // Process Sensor usage
+        final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
+        final int NSE = sensorStats.size();
+        for (int ise = 0; ise < NSE; ise++) {
+            final BatteryStats.Uid.Sensor sensor = sensorStats.valueAt(ise);
+            final int sensorHandle = sensorStats.keyAt(ise);
+            final BatteryStats.Timer timer = sensor.getSensorTime();
+            final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+            switch (sensorHandle) {
+                case BatteryStats.Uid.Sensor.GPS:
+                    app.gpsTimeMs = sensorTime;
+                    app.gpsPowerMah = (app.gpsTimeMs * mGpsPowerOn) / (1000*60*60);
+                    break;
+                default:
+                    final int sensorsCount = mSensors.size();
+                    for (int i = 0; i < sensorsCount; i++) {
+                        final Sensor s = mSensors.get(i);
+                        if (s.getHandle() == sensorHandle) {
+                            app.sensorPowerMah += (sensorTime * s.getPower()) / (1000*60*60);
+                            break;
+                        }
+                    }
+                    break;
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/os/WakelockPowerCalculator.java b/core/java/com/android/internal/os/WakelockPowerCalculator.java
new file mode 100644
index 0000000..7575010f
--- /dev/null
+++ b/core/java/com/android/internal/os/WakelockPowerCalculator.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.ArrayMap;
+import android.util.Log;
+
+public class WakelockPowerCalculator extends PowerCalculator {
+    private static final String TAG = "WakelockPowerCalculator";
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+    private final double mPowerWakelock;
+    private long mTotalAppWakelockTimeMs = 0;
+
+    public WakelockPowerCalculator(PowerProfile profile) {
+        mPowerWakelock = profile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawUptimeUs,
+                             long rawRealtimeUs, int statsType) {
+        long wakeLockTimeUs = 0;
+        final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelockStats =
+                u.getWakelockStats();
+        final int wakelockStatsCount = wakelockStats.size();
+        for (int i = 0; i < wakelockStatsCount; i++) {
+            final BatteryStats.Uid.Wakelock wakelock = wakelockStats.valueAt(i);
+
+            // Only care about partial wake locks since full wake locks
+            // are canceled when the user turns the screen off.
+            BatteryStats.Timer timer = wakelock.getWakeTime(BatteryStats.WAKE_TYPE_PARTIAL);
+            if (timer != null) {
+                wakeLockTimeUs += timer.getTotalTimeLocked(rawRealtimeUs, statsType);
+            }
+        }
+        app.wakeLockTimeMs = wakeLockTimeUs / 1000; // convert to millis
+        mTotalAppWakelockTimeMs += app.wakeLockTimeMs;
+
+        // Add cost of holding a wake lock.
+        app.wakeLockPowerMah = (app.wakeLockTimeMs * mPowerWakelock) / (1000*60*60);
+        if (DEBUG && app.wakeLockPowerMah != 0) {
+            Log.d(TAG, "UID " + u.getUid() + ": wake " + app.wakeLockTimeMs
+                    + " power=" + BatteryStatsHelper.makemAh(app.wakeLockPowerMah));
+        }
+    }
+
+    @Override
+    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+                                   long rawUptimeUs, int statsType) {
+        long wakeTimeMillis = stats.getBatteryUptime(rawUptimeUs) / 1000;
+        wakeTimeMillis -= mTotalAppWakelockTimeMs
+                + (stats.getScreenOnTime(rawRealtimeUs, statsType) / 1000);
+        if (wakeTimeMillis > 0) {
+            final double power = (wakeTimeMillis * mPowerWakelock) / (1000*60*60);
+            if (DEBUG) {
+                Log.d(TAG, "OS wakeLockTime " + wakeTimeMillis + " power "
+                        + BatteryStatsHelper.makemAh(power));
+            }
+            app.wakeLockTimeMs += wakeTimeMillis;
+            app.wakeLockPowerMah += power;
+        }
+    }
+
+    @Override
+    public void reset() {
+        mTotalAppWakelockTimeMs = 0;
+    }
+}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
new file mode 100644
index 0000000..4fb8b55
--- /dev/null
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+import android.util.Log;
+
+/**
+ * WiFi power calculator for when BatteryStats supports energy reporting
+ * from the WiFi controller.
+ */
+public class WifiPowerCalculator extends PowerCalculator {
+    private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
+    private static final String TAG = "WifiPowerCalculator";
+    private final double mIdleCurrentMa;
+    private final double mTxCurrentMa;
+    private final double mRxCurrentMa;
+    private double mTotalAppPowerDrain = 0;
+
+    public WifiPowerCalculator(PowerProfile profile) {
+        mIdleCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_IDLE);
+        mTxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_TX);
+        mRxCurrentMa = profile.getAveragePower(PowerProfile.POWER_WIFI_CONTROLLER_RX);
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+        final long idleTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME,
+                statsType);
+        final long txTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME, statsType);
+        final long rxTime = u.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME, statsType);
+        app.wifiRunningTimeMs = idleTime + rxTime + txTime;
+        app.wifiPowerMah =
+                ((idleTime * mIdleCurrentMa) + (txTime * mTxCurrentMa) + (rxTime * mRxCurrentMa))
+                / (1000*60*60);
+        mTotalAppPowerDrain += app.wifiPowerMah;
+
+        app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
+                statsType);
+        app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
+                statsType);
+        app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
+                statsType);
+        app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
+                statsType);
+    }
+
+    @Override
+    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+                                   long rawUptimeUs, int statsType) {
+        final long idleTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_IDLE_TIME,
+                statsType);
+        final long rxTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_RX_TIME,
+                statsType);
+        final long txTimeMs = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_TX_TIME,
+                statsType);
+        app.wifiRunningTimeMs = idleTimeMs + rxTimeMs + txTimeMs;
+
+        double powerDrain = stats.getWifiControllerActivity(BatteryStats.CONTROLLER_POWER_DRAIN,
+                statsType) / (1000*60*60);
+        if (powerDrain == 0) {
+            // Some controllers do not report power drain, so we can calculate it here.
+            powerDrain = ((idleTimeMs * mIdleCurrentMa) + (txTimeMs * mTxCurrentMa)
+                    + (rxTimeMs * mRxCurrentMa)) / (1000*60*60);
+        }
+        app.wifiPowerMah = Math.max(0, powerDrain - mTotalAppPowerDrain);
+
+        if (DEBUG) {
+            Log.d(TAG, "left over WiFi power: " + BatteryStatsHelper.makemAh(app.wifiPowerMah));
+        }
+    }
+
+    @Override
+    public void reset() {
+        mTotalAppPowerDrain = 0;
+    }
+}
diff --git a/core/java/com/android/internal/os/WifiPowerEstimator.java b/core/java/com/android/internal/os/WifiPowerEstimator.java
new file mode 100644
index 0000000..0172367
--- /dev/null
+++ b/core/java/com/android/internal/os/WifiPowerEstimator.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.internal.os;
+
+import android.os.BatteryStats;
+
+/**
+ * Estimates WiFi power usage based on timers in BatteryStats.
+ */
+public class WifiPowerEstimator extends PowerCalculator {
+    private final double mWifiPowerPerPacket;
+    private final double mWifiPowerOn;
+    private final double mWifiPowerScan;
+    private final double mWifiPowerBatchScan;
+    private long mTotalAppWifiRunningTimeMs = 0;
+
+    public WifiPowerEstimator(PowerProfile profile) {
+        mWifiPowerPerPacket = getWifiPowerPerPacket(profile);
+        mWifiPowerOn = profile.getAveragePower(PowerProfile.POWER_WIFI_ON);
+        mWifiPowerScan = profile.getAveragePower(PowerProfile.POWER_WIFI_SCAN);
+        mWifiPowerBatchScan = profile.getAveragePower(PowerProfile.POWER_WIFI_BATCHED_SCAN);
+    }
+
+    /**
+     * Return estimated power (in mAs) of sending a byte with the Wi-Fi radio.
+     */
+    private static double getWifiPowerPerPacket(PowerProfile profile) {
+        final long WIFI_BPS = 1000000; // TODO: Extract average bit rates from system
+        final double WIFI_POWER = profile.getAveragePower(PowerProfile.POWER_WIFI_ACTIVE)
+                / 3600;
+        return (WIFI_POWER / (((double)WIFI_BPS) / 8 / 2048)) / (60*60);
+    }
+
+    @Override
+    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
+                             long rawUptimeUs, int statsType) {
+        app.wifiRxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_RX_DATA,
+                statsType);
+        app.wifiTxPackets = u.getNetworkActivityPackets(BatteryStats.NETWORK_WIFI_TX_DATA,
+                statsType);
+        app.wifiRxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_RX_DATA,
+                statsType);
+        app.wifiTxBytes = u.getNetworkActivityBytes(BatteryStats.NETWORK_WIFI_TX_DATA,
+                statsType);
+
+        final double wifiPacketPower = (app.wifiRxPackets + app.wifiTxPackets)
+                * mWifiPowerPerPacket;
+
+        app.wifiRunningTimeMs = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
+        mTotalAppWifiRunningTimeMs += app.wifiRunningTimeMs;
+        final double wifiLockPower = (app.wifiRunningTimeMs * mWifiPowerOn) / (1000*60*60);
+
+        final long wifiScanTimeMs = u.getWifiScanTime(rawRealtimeUs, statsType);
+        final double wifiScanPower = (wifiScanTimeMs * mWifiPowerScan) / (1000*60*60);
+
+        double wifiBatchScanPower = 0;
+        for (int bin = 0; bin < BatteryStats.Uid.NUM_WIFI_BATCHED_SCAN_BINS; bin++) {
+            final long batchScanTimeMs =
+                    u.getWifiBatchedScanTime(bin, rawRealtimeUs, statsType) / 1000;
+            final double batchScanPower = (batchScanTimeMs * mWifiPowerBatchScan) / (1000*60*60);
+            wifiBatchScanPower += batchScanPower;
+        }
+
+        app.wifiPowerMah = wifiPacketPower + wifiLockPower + wifiScanPower + wifiBatchScanPower;
+    }
+
+    @Override
+    public void calculateRemaining(BatterySipper app, BatteryStats stats, long rawRealtimeUs,
+                                   long rawUptimeUs, int statsType) {
+        final long totalRunningTimeMs = stats.getGlobalWifiRunningTime(rawRealtimeUs, statsType)
+                / 1000;
+        final double powerDrain = ((totalRunningTimeMs - mTotalAppWifiRunningTimeMs) * mWifiPowerOn)
+                / (1000*60*60);
+        app.wifiRunningTimeMs = totalRunningTimeMs;
+        app.wifiPowerMah = Math.max(0, powerDrain);
+    }
+
+    @Override
+    public void reset() {
+        mTotalAppWifiRunningTimeMs = 0;
+    }
+}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 49d565d..3ad4f1c 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -32,6 +32,7 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.system.StructPollfd;
+import android.text.Hyphenator;
 import android.util.EventLog;
 import android.util.Log;
 import android.webkit.WebViewFactory;
@@ -182,6 +183,7 @@
         preloadResources();
         preloadOpenGL();
         preloadSharedLibraries();
+        preloadTextResources();
         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
         // for memory sharing purposes.
         WebViewFactory.prepareWebViewInZygote();
@@ -201,6 +203,10 @@
         }
     }
 
+    private static void preloadTextResources() {
+        Hyphenator.init();
+    }
+
     /**
      * Performs Zygote process initialization. Loads and initializes
      * commonly used classes.
@@ -461,12 +467,11 @@
 
         try {
             for (String classPathElement : classPathElements) {
-                final byte dexopt = DexFile.isDexOptNeededInternal(classPathElement, "*", instructionSet,
-                        false /* defer */);
-                if (dexopt == DexFile.DEXOPT_NEEDED) {
-                    installer.dexopt(classPathElement, Process.SYSTEM_UID, false, instructionSet);
-                } else if (dexopt == DexFile.PATCHOAT_NEEDED) {
-                    installer.patchoat(classPathElement, Process.SYSTEM_UID, false, instructionSet);
+                final int dexoptNeeded = DexFile.getDexOptNeeded(
+                        classPathElement, "*", instructionSet, false /* defer */);
+                if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+                    installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
+                            instructionSet, dexoptNeeded);
                 }
             }
         } catch (IOException ioe) {
diff --git a/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java b/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java
index a529923..1d0511f 100644
--- a/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java
+++ b/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java
@@ -4,18 +4,12 @@
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Context;
-import android.content.DialogInterface;
 import android.content.Intent;
-import android.os.Environment;
 import android.os.IBinder;
 import android.os.PowerManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.storage.IMountService;
-import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageVolume;
-import android.util.Log;
+import android.util.Slog;
 import android.view.WindowManager;
 import android.widget.Toast;
 
@@ -24,8 +18,7 @@
 /**
  * Takes care of unmounting and formatting external storage.
  */
-public class ExternalStorageFormatter extends Service
-        implements DialogInterface.OnCancelListener {
+public class ExternalStorageFormatter extends Service {
     static final String TAG = "ExternalStorageFormatter";
 
     public static final String FORMAT_ONLY = "com.android.internal.os.storage.FORMAT_ONLY";
@@ -33,16 +26,10 @@
 
     public static final String EXTRA_ALWAYS_RESET = "always_reset";
 
-    // If non-null, the volume to format. Otherwise, will use the default external storage directory
-    private StorageVolume mStorageVolume;
-
     public static final ComponentName COMPONENT_NAME
             = new ComponentName("android", ExternalStorageFormatter.class.getName());
 
-    // Access using getMountService()
-    private IMountService mMountService = null;
-
-    private StorageManager mStorageManager = null;
+    private StorageManager mStorageManager;
 
     private PowerManager.WakeLock mWakeLock;
 
@@ -52,24 +39,11 @@
     private boolean mAlwaysReset = false;
     private String mReason = null;
 
-    StorageEventListener mStorageListener = new StorageEventListener() {
-        @Override
-        public void onStorageStateChanged(String path, String oldState, String newState) {
-            Log.i(TAG, "Received storage state changed notification that " +
-                    path + " changed state from " + oldState +
-                    " to " + newState);
-            updateProgressState();
-        }
-    };
-
     @Override
     public void onCreate() {
         super.onCreate();
 
-        if (mStorageManager == null) {
-            mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
-            mStorageManager.registerListener(mStorageListener);
-        }
+        mStorageManager = getSystemService(StorageManager.class);
 
         mWakeLock = ((PowerManager)getSystemService(Context.POWER_SERVICE))
                 .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExternalStorageFormatter");
@@ -86,28 +60,74 @@
         }
 
         mReason = intent.getStringExtra(Intent.EXTRA_REASON);
-        mStorageVolume = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
-
-        if (mProgressDialog == null) {
-            mProgressDialog = new ProgressDialog(this);
-            mProgressDialog.setIndeterminate(true);
-            mProgressDialog.setCancelable(true);
-            mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            if (!mAlwaysReset) {
-                mProgressDialog.setOnCancelListener(this);
-            }
-            updateProgressState();
-            mProgressDialog.show();
+        StorageVolume userVol = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
+        if (userVol == null) {
+            Slog.w(TAG, "Missing explicit storage volume; assuming default");
+            userVol = mStorageManager.getPrimaryVolume();
         }
 
+        final String volumeId = userVol.getId();
+
+        mProgressDialog = new ProgressDialog(this);
+        mProgressDialog.setIndeterminate(true);
+        mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+        mProgressDialog.setMessage(getText(R.string.progress_unmounting));
+        mProgressDialog.show();
+
+        new FormatTask(volumeId).start();
+
         return Service.START_REDELIVER_INTENT;
     }
 
+    private class FormatTask extends Thread {
+        private final String mVolumeId;
+
+        public FormatTask(String volumeId) {
+            mVolumeId = volumeId;
+        }
+
+        @Override
+        public void run() {
+            boolean success = false;
+            try {
+                mStorageManager.format(mVolumeId);
+                success = true;
+            } catch (Exception e) {
+                Slog.w(TAG, "Failed to format", e);
+                Toast.makeText(ExternalStorageFormatter.this,
+                        R.string.format_error, Toast.LENGTH_LONG).show();
+            }
+            if (success) {
+                if (mFactoryReset) {
+                    Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
+                    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                    intent.putExtra(Intent.EXTRA_REASON, mReason);
+                    sendBroadcast(intent);
+                    // Intent handling is asynchronous -- assume it will happen soon.
+                    stopSelf();
+                    return;
+                }
+            }
+            // If we didn't succeed, or aren't doing a full factory
+            // reset, then it is time to remount the storage.
+            if (!success && mAlwaysReset) {
+                Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
+                intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                intent.putExtra(Intent.EXTRA_REASON, mReason);
+                sendBroadcast(intent);
+            } else {
+                try {
+                    mStorageManager.mount(mVolumeId);
+                } catch (Exception e) {
+                    Slog.w(TAG, "Failed to mount", e);
+                }
+            }
+            stopSelf();
+        }
+    }
+
     @Override
     public void onDestroy() {
-        if (mStorageManager != null) {
-            mStorageManager.unregisterListener(mStorageListener);
-        }
         if (mProgressDialog != null) {
             mProgressDialog.dismiss();
         }
@@ -119,137 +139,4 @@
     public IBinder onBind(Intent intent) {
         return null;
     }
-
-    @Override
-    public void onCancel(DialogInterface dialog) {
-        IMountService mountService = getMountService();
-        String extStoragePath = mStorageVolume == null ?
-                Environment.getLegacyExternalStorageDirectory().toString() :
-                mStorageVolume.getPath();
-        try {
-            mountService.mountVolume(extStoragePath);
-        } catch (RemoteException e) {
-            Log.w(TAG, "Failed talking with mount service", e);
-        }
-        stopSelf();
-    }
-
-    void fail(int msg) {
-        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
-        if (mAlwaysReset) {
-            Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
-            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-            intent.putExtra(Intent.EXTRA_REASON, mReason);
-            sendBroadcast(intent);
-        }
-        stopSelf();
-    }
-
-    void updateProgressState() {
-        String status = mStorageVolume == null ?
-                Environment.getExternalStorageState() :
-                mStorageManager.getVolumeState(mStorageVolume.getPath());
-        if (Environment.MEDIA_MOUNTED.equals(status)
-                || Environment.MEDIA_MOUNTED_READ_ONLY.equals(status)) {
-            updateProgressDialog(R.string.progress_unmounting);
-            IMountService mountService = getMountService();
-            final String extStoragePath = mStorageVolume == null ?
-                    Environment.getLegacyExternalStorageDirectory().toString() :
-                    mStorageVolume.getPath();
-            try {
-                // Remove encryption mapping if this is an unmount for a factory reset.
-                mountService.unmountVolume(extStoragePath, true, mFactoryReset);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failed talking with mount service", e);
-            }
-        } else if (Environment.MEDIA_NOFS.equals(status)
-                || Environment.MEDIA_UNMOUNTED.equals(status)
-                || Environment.MEDIA_UNMOUNTABLE.equals(status)) {
-            updateProgressDialog(R.string.progress_erasing);
-            final IMountService mountService = getMountService();
-            final String extStoragePath = mStorageVolume == null ?
-                    Environment.getLegacyExternalStorageDirectory().toString() :
-                    mStorageVolume.getPath();
-            if (mountService != null) {
-                new Thread() {
-                    @Override
-                    public void run() {
-                        boolean success = false;
-                        try {
-                            mountService.formatVolume(extStoragePath);
-                            success = true;
-                        } catch (Exception e) {
-                            Toast.makeText(ExternalStorageFormatter.this,
-                                    R.string.format_error, Toast.LENGTH_LONG).show();
-                        }
-                        if (success) {
-                            if (mFactoryReset) {
-                                Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
-                                intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                                intent.putExtra(Intent.EXTRA_REASON, mReason);
-                                sendBroadcast(intent);
-                                // Intent handling is asynchronous -- assume it will happen soon.
-                                stopSelf();
-                                return;
-                            }
-                        }
-                        // If we didn't succeed, or aren't doing a full factory
-                        // reset, then it is time to remount the storage.
-                        if (!success && mAlwaysReset) {
-                            Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
-                            intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                            intent.putExtra(Intent.EXTRA_REASON, mReason);
-                            sendBroadcast(intent);
-                        } else {
-                            try {
-                                mountService.mountVolume(extStoragePath);
-                            } catch (RemoteException e) {
-                                Log.w(TAG, "Failed talking with mount service", e);
-                            }
-                        }
-                        stopSelf();
-                        return;
-                    }
-                }.start();
-            } else {
-                Log.w(TAG, "Unable to locate IMountService");
-            }
-        } else if (Environment.MEDIA_BAD_REMOVAL.equals(status)) {
-            fail(R.string.media_bad_removal);
-        } else if (Environment.MEDIA_CHECKING.equals(status)) {
-            fail(R.string.media_checking);
-        } else if (Environment.MEDIA_REMOVED.equals(status)) {
-            fail(R.string.media_removed);
-        } else if (Environment.MEDIA_SHARED.equals(status)) {
-            fail(R.string.media_shared);
-        } else {
-            fail(R.string.media_unknown_state);
-            Log.w(TAG, "Unknown storage state: " + status);
-            stopSelf();
-        }
-    }
-
-    public void updateProgressDialog(int msg) {
-        if (mProgressDialog == null) {
-            mProgressDialog = new ProgressDialog(this);
-            mProgressDialog.setIndeterminate(true);
-            mProgressDialog.setCancelable(false);
-            mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
-            mProgressDialog.show();
-        }
-
-        mProgressDialog.setMessage(getText(msg));
-    }
-
-    IMountService getMountService() {
-        if (mMountService == null) {
-            IBinder service = ServiceManager.getService("mount");
-            if (service != null) {
-                mMountService = IMountService.Stub.asInterface(service);
-            } else {
-                Log.e(TAG, "Can't get mount service");
-            }
-        }
-        return mMountService;
-    }
 }
diff --git a/core/java/com/android/internal/util/ImageUtils.java b/core/java/com/android/internal/util/ImageUtils.java
index c153904..7d56e9e 100644
--- a/core/java/com/android/internal/util/ImageUtils.java
+++ b/core/java/com/android/internal/util/ImageUtils.java
@@ -17,10 +17,13 @@
 package com.android.internal.util;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 
 /**
  * Utility class for image analysis and processing.
@@ -117,4 +120,40 @@
                 && Math.abs(r - b) < TOLERANCE
                 && Math.abs(g - b) < TOLERANCE;
     }
+
+    /**
+     * Convert a drawable to a bitmap, scaled to fit within maxWidth and maxHeight.
+     */
+    public static Bitmap buildScaledBitmap(Drawable drawable, int maxWidth,
+            int maxHeight) {
+        if (drawable == null) {
+            return null;
+        }
+        int originalWidth = drawable.getIntrinsicWidth();
+        int originalHeight = drawable.getIntrinsicHeight();
+
+        if ((originalWidth <= maxWidth) && (originalHeight <= maxHeight) &&
+                (drawable instanceof BitmapDrawable)) {
+            return ((BitmapDrawable) drawable).getBitmap();
+        }
+        if (originalHeight <= 0 || originalWidth <= 0) {
+            return null;
+        }
+
+        // create a new bitmap, scaling down to fit the max dimensions of
+        // a large notification icon if necessary
+        float ratio = Math.min((float) maxWidth / (float) originalWidth,
+                (float) maxHeight / (float) originalHeight);
+        ratio = Math.min(1.0f, ratio);
+        int scaledWidth = (int) (ratio * originalWidth);
+        int scaledHeight = (int) (ratio * originalHeight);
+        Bitmap result = Bitmap.createBitmap(scaledWidth, scaledHeight, Config.ARGB_8888);
+
+        // and paint our app bitmap on it
+        Canvas canvas = new Canvas(result);
+        drawable.setBounds(0, 0, scaledWidth, scaledHeight);
+        drawable.draw(canvas);
+
+        return result;
+    }
 }
diff --git a/core/java/com/android/internal/util/IndentingPrintWriter.java b/core/java/com/android/internal/util/IndentingPrintWriter.java
index 6fddd09..f1add27 100644
--- a/core/java/com/android/internal/util/IndentingPrintWriter.java
+++ b/core/java/com/android/internal/util/IndentingPrintWriter.java
@@ -18,6 +18,7 @@
 
 import java.io.PrintWriter;
 import java.io.Writer;
+import java.util.Arrays;
 
 /**
  * Lightweight wrapper around {@link PrintWriter} that automatically indents
@@ -68,6 +69,10 @@
         print(key + "=" + String.valueOf(value) + " ");
     }
 
+    public void printPair(String key, Object[] value) {
+        print(key + "=" + Arrays.toString(value) + " ");
+    }
+
     public void printHexPair(String key, int value) {
         print(key + "=0x" + Integer.toHexString(value) + " ");
     }
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
new file mode 100644
index 0000000..aacdb34
--- /dev/null
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.widget.FloatingToolbar;
+
+public class FloatingActionMode extends ActionMode {
+
+    private final Context mContext;
+    private final ActionMode.Callback2 mCallback;
+    private final MenuBuilder mMenu;
+    private final FloatingToolbar mFloatingToolbar;
+    private final Rect mContentRect;
+    private final Rect mContentRectOnWindow;
+    private final Rect mPreviousContentRectOnWindow;
+    private final int[] mViewPosition;
+    private final View mOriginatingView;
+
+    public FloatingActionMode(
+            Context context, ActionMode.Callback2 callback, View originatingView,
+            FloatingToolbar floatingToolbar) {
+        mContext = context;
+        mCallback = callback;
+        mMenu = new MenuBuilder(context).setDefaultShowAsAction(
+                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mFloatingToolbar = floatingToolbar
+                .setMenu(mMenu)
+                .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
+                        @Override
+                    public boolean onMenuItemClick(MenuItem item) {
+                        return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+                    }
+                });
+        setType(ActionMode.TYPE_FLOATING);
+        mContentRect = new Rect();
+        mContentRectOnWindow = new Rect();
+        mPreviousContentRectOnWindow = new Rect();
+        mViewPosition = new int[2];
+        mOriginatingView = originatingView;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {}
+
+    @Override
+    public void setTitle(int resId) {}
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {}
+
+    @Override
+    public void setSubtitle(int resId) {}
+
+    @Override
+    public void setCustomView(View view) {}
+
+    @Override
+    public void invalidate() {
+        mCallback.onPrepareActionMode(this, mMenu);
+        mFloatingToolbar.updateLayout();
+        invalidateContentRect();
+    }
+
+    @Override
+    public void invalidateContentRect() {
+        mCallback.onGetContentRect(this, mOriginatingView, mContentRect);
+        repositionToolbar();
+    }
+
+    public void updateViewLocationInWindow() {
+        mOriginatingView.getLocationInWindow(mViewPosition);
+        repositionToolbar();
+    }
+
+    private void repositionToolbar() {
+        mContentRectOnWindow.set(
+                mContentRect.left + mViewPosition[0],
+                mContentRect.top + mViewPosition[1],
+                mContentRect.right + mViewPosition[0],
+                mContentRect.bottom + mViewPosition[1]);
+        if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
+            mFloatingToolbar.setContentRect(mContentRectOnWindow);
+            mFloatingToolbar.updateLayout();
+        }
+        mPreviousContentRectOnWindow.set(mContentRectOnWindow);
+    }
+
+    @Override
+    public void finish() {
+        mCallback.onDestroyActionMode(this);
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return null;
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return null;
+    }
+
+    @Override
+    public View getCustomView() {
+        return null;
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return new MenuInflater(mContext);
+    }
+
+}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index be9945d..2219ad1 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -24,7 +24,9 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
+import android.util.Size;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -32,19 +34,28 @@
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
 import android.view.Window;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.Transformation;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
+import android.widget.ListView;
 import android.widget.PopupWindow;
-
-import com.android.internal.R;
-import com.android.internal.util.Preconditions;
+import android.widget.TextView;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
 
+import com.android.internal.R;
+import com.android.internal.util.Preconditions;
+
 /**
  * A floating toolbar for showing contextual menu items.
  * This view shows as many menu item buttons as can fit in the horizontal toolbar and the
@@ -53,6 +64,9 @@
  */
 public final class FloatingToolbar {
 
+    // This class is responsible for the public API of the floating toolbar.
+    // It delegates rendering operations to the FloatingToolbarPopup.
+
     private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
             new MenuItem.OnMenuItemClickListener() {
                 @Override
@@ -63,17 +77,6 @@
 
     private final Context mContext;
     private final FloatingToolbarPopup mPopup;
-    private final ViewGroup mMenuItemButtonsContainer;
-    private final View.OnClickListener mMenuItemButtonOnClickListener =
-            new View.OnClickListener() {
-                @Override
-                public void onClick(View v) {
-                    if (v.getTag() instanceof MenuItem) {
-                        mMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
-                        mPopup.dismiss();
-                    }
-                }
-            };
 
     private final Rect mContentRect = new Rect();
     private final Point mCoordinates = new Point();
@@ -81,17 +84,17 @@
     private Menu mMenu;
     private List<CharSequence> mShowingTitles = new ArrayList<CharSequence>();
     private MenuItem.OnMenuItemClickListener mMenuItemClickListener = NO_OP_MENUITEM_CLICK_LISTENER;
-    private View mOpenOverflowButton;
 
     private int mSuggestedWidth;
+    private boolean mWidthChanged = true;
+    private int mOverflowDirection;
 
     /**
      * Initializes a floating toolbar.
      */
     public FloatingToolbar(Context context, Window window) {
         mContext = Preconditions.checkNotNull(context);
-        mPopup = new FloatingToolbarPopup(Preconditions.checkNotNull(window.getDecorView()));
-        mMenuItemButtonsContainer = createMenuButtonsContainer(context);
+        mPopup = new FloatingToolbarPopup(window.getDecorView());
     }
 
     /**
@@ -137,6 +140,10 @@
      * toolbar.
      */
     public FloatingToolbar setSuggestedWidth(int suggestedWidth) {
+        // Check if there's been a substantial width spec change.
+        int difference = Math.abs(suggestedWidth - mSuggestedWidth);
+        mWidthChanged = difference > (mSuggestedWidth * 0.2);
+
         mSuggestedWidth = suggestedWidth;
         return this;
     }
@@ -146,16 +153,18 @@
      */
     public FloatingToolbar show() {
         List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
-        if (hasContentChanged(menuItems) || hasWidthChanged()) {
+        if (!isCurrentlyShowing(menuItems) || mWidthChanged) {
             mPopup.dismiss();
-            layoutMenuItemButtons(menuItems);
+            mPopup.layoutMenuItems(menuItems, mMenuItemClickListener, mSuggestedWidth);
             mShowingTitles = getMenuItemTitles(menuItems);
         }
         refreshCoordinates();
+        mPopup.setOverflowDirection(mOverflowDirection);
         mPopup.updateCoordinates(mCoordinates.x, mCoordinates.y);
         if (!mPopup.isShowing()) {
             mPopup.show(mCoordinates.x, mCoordinates.y);
         }
+        mWidthChanged = false;
         return this;
     }
 
@@ -189,45 +198,26 @@
      * Refreshes {@link #mCoordinates} with values based on {@link #mContentRect}.
      */
     private void refreshCoordinates() {
-        int popupWidth = mPopup.getWidth();
-        int popupHeight = mPopup.getHeight();
-        if (!mPopup.isShowing()) {
-            // Popup isn't yet shown, get estimated size from the menu item buttons container.
-            mMenuItemButtonsContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-            popupWidth = mMenuItemButtonsContainer.getMeasuredWidth();
-            popupHeight = mMenuItemButtonsContainer.getMeasuredHeight();
-        }
-        int x = mContentRect.centerX() - popupWidth / 2;
+        int x = mContentRect.centerX() - mPopup.getWidth() / 2;
         int y;
-        if (shouldDisplayAtTopOfContent()) {
-            y = mContentRect.top - popupHeight;
+        if (mContentRect.top > mPopup.getHeight()) {
+            y = mContentRect.top - mPopup.getHeight();
+            mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_UP;
+        } else if (mContentRect.top > getEstimatedToolbarHeight(mContext)) {
+            y = mContentRect.top - getEstimatedToolbarHeight(mContext);
+            mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
         } else {
             y = mContentRect.bottom;
+            mOverflowDirection = FloatingToolbarPopup.OVERFLOW_DIRECTION_DOWN;
         }
         mCoordinates.set(x, y);
     }
 
     /**
-     * Returns true if this floating toolbar's menu items have been reordered or changed.
+     * Returns true if this floating toolbar is currently showing the specified menu items.
      */
-    private boolean hasContentChanged(List<MenuItem> menuItems) {
-        return !mShowingTitles.equals(getMenuItemTitles(menuItems));
-    }
-
-    /**
-     * Returns true if there is a significant change in width of the toolbar.
-     */
-    private boolean hasWidthChanged() {
-        int actualWidth = mPopup.getWidth();
-        int difference = Math.abs(actualWidth - mSuggestedWidth);
-        return difference > (actualWidth * 0.2);
-    }
-
-    /**
-     * Returns true if the preferred positioning of the toolbar is above the content rect.
-     */
-    private boolean shouldDisplayAtTopOfContent() {
-        return mContentRect.top - getMinimumOverflowHeight(mContext) > 0;
+    private boolean isCurrentlyShowing(List<MenuItem> menuItems) {
+        return mShowingTitles.equals(getMenuItemTitles(menuItems));
     }
 
     /**
@@ -258,83 +248,767 @@
         return titles;
     }
 
-    private void layoutMenuItemButtons(List<MenuItem> menuItems) {
-        final int toolbarWidth = getAdjustedToolbarWidth(mContext, mSuggestedWidth)
-                // Reserve space for the "open overflow" button.
-                - getEstimatedOpenOverflowButtonWidth(mContext);
 
-        int availableWidth = toolbarWidth;
-        LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
+    /**
+     * A popup window used by the floating toolbar.
+     *
+     * This class is responsible for the rendering/animation of the floating toolbar.
+     * It can hold one of 2 panels (i.e. main panel and overflow panel) at a time.
+     * It delegates specific panel functionality to the appropriate panel.
+     */
+    private static final class FloatingToolbarPopup {
 
-        mMenuItemButtonsContainer.removeAllViews();
+        public static final int OVERFLOW_DIRECTION_UP = 0;
+        public static final int OVERFLOW_DIRECTION_DOWN = 1;
 
-        boolean isFirstItem = true;
-        while (!remainingMenuItems.isEmpty()) {
-            final MenuItem menuItem = remainingMenuItems.peek();
-            Button menuItemButton = createMenuItemButton(mContext, menuItem);
+        private final View mParent;
+        private final PopupWindow mPopupWindow;
+        private final ViewGroup mContentContainer;
+        private final int mPadding;
 
-            // Adding additional left padding for the first button to even out button spacing.
-            if (isFirstItem) {
-                menuItemButton.setPadding(
-                        2 * menuItemButton.getPaddingLeft(),
-                        menuItemButton.getPaddingTop(),
-                        menuItemButton.getPaddingRight(),
-                        menuItemButton.getPaddingBottom());
-                isFirstItem = false;
+        private final Animation.AnimationListener mOnOverflowOpened =
+                new Animation.AnimationListener() {
+                    @Override
+                    public void onAnimationStart(Animation animation) {}
+
+                    @Override
+                    public void onAnimationEnd(Animation animation) {
+                        // This animation should never be run if the overflow panel has not been
+                        // initialized.
+                        Preconditions.checkNotNull(mOverflowPanel);
+                        mContentContainer.removeAllViews();
+                        mContentContainer.addView(mOverflowPanel.getView());
+                        mOverflowPanel.fadeIn(true);
+                        setContentAreaAsTouchableSurface();
+                    }
+
+                    @Override
+                    public void onAnimationRepeat(Animation animation) {}
+                };
+        private final Animation.AnimationListener mOnOverflowClosed =
+                new Animation.AnimationListener() {
+                    @Override
+                    public void onAnimationStart(Animation animation) {}
+
+                    @Override
+                    public void onAnimationEnd(Animation animation) {
+                        // This animation should never be run if the main panel has not been
+                        // initialized.
+                        Preconditions.checkNotNull(mMainPanel);
+                        mContentContainer.removeAllViews();
+                        mContentContainer.addView(mMainPanel.getView());
+                        mMainPanel.fadeIn(true);
+                        setContentAreaAsTouchableSurface();
+                    }
+
+                    @Override
+                    public void onAnimationRepeat(Animation animation) {
+                    }
+                };
+        private final AnimatorSet mGrowFadeInFromBottomAnimation;
+        private final AnimatorSet mShrinkFadeOutFromBottomAnimation;
+
+        private final Runnable mOpenOverflow = new Runnable() {
+            @Override
+            public void run() {
+                openOverflow();
+            }
+        };
+        private final Runnable mCloseOverflow = new Runnable() {
+            @Override
+            public void run() {
+                closeOverflow();
+            }
+        };
+
+        private final Region mTouchableRegion = new Region();
+
+        private boolean mDismissAnimating;
+
+        private FloatingToolbarOverflowPanel mOverflowPanel;
+        private FloatingToolbarMainPanel mMainPanel;
+        private int mOverflowDirection;
+
+        /**
+         * Initializes a new floating toolbar popup.
+         *
+         * @param parent  A parent view to get the {@link android.view.View#getWindowToken()} token
+         *      from.
+         */
+        public FloatingToolbarPopup(View parent) {
+            mParent = Preconditions.checkNotNull(parent);
+            mContentContainer = createContentContainer(parent.getContext());
+            mPopupWindow = createPopupWindow(mContentContainer);
+            mGrowFadeInFromBottomAnimation = createGrowFadeInFromBottom(mContentContainer);
+            mShrinkFadeOutFromBottomAnimation = createShrinkFadeOutFromBottomAnimation(
+                    mContentContainer,
+                    new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            mPopupWindow.dismiss();
+                            mDismissAnimating = false;
+                            setMainPanelAsContent();
+                        }
+                    });
+            // Make the touchable area of this popup be the area specified by mTouchableRegion.
+            mPopupWindow.getContentView()
+                    .getRootView()
+                    .getViewTreeObserver()
+                    .addOnComputeInternalInsetsListener(
+                            new ViewTreeObserver.OnComputeInternalInsetsListener() {
+                                public void onComputeInternalInsets(
+                                        ViewTreeObserver.InternalInsetsInfo info) {
+                                    info.contentInsets.setEmpty();
+                                    info.visibleInsets.setEmpty();
+                                    info.touchableRegion.set(mTouchableRegion);
+                                    info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo
+                                            .TOUCHABLE_INSETS_REGION);
+                                }
+                            });
+            mPadding = parent.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_margin);
+        }
+
+        /**
+         * Lays out buttons for the specified menu items.
+         */
+        public void layoutMenuItems(List<MenuItem> menuItems,
+                MenuItem.OnMenuItemClickListener menuItemClickListener, int suggestedWidth) {
+            mContentContainer.removeAllViews();
+            if (mMainPanel == null) {
+                mMainPanel = new FloatingToolbarMainPanel(mParent.getContext(), mOpenOverflow);
+            }
+            List<MenuItem> overflowMenuItems =
+                    mMainPanel.layoutMenuItems(menuItems, suggestedWidth);
+            mMainPanel.setOnMenuItemClickListener(menuItemClickListener);
+            if (!overflowMenuItems.isEmpty()) {
+                if (mOverflowPanel == null) {
+                    mOverflowPanel =
+                            new FloatingToolbarOverflowPanel(mParent.getContext(), mCloseOverflow);
+                }
+                mOverflowPanel.setMenuItems(overflowMenuItems);
+                mOverflowPanel.setOnMenuItemClickListener(menuItemClickListener);
+            }
+            updatePopupSize();
+        }
+
+        /**
+         * Shows this popup at the specified coordinates.
+         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+         */
+        public void show(int x, int y) {
+            if (isShowing()) {
+                return;
             }
 
-            // Adding additional right padding for the last button to even out button spacing.
-            if (remainingMenuItems.size() == 1) {
-                menuItemButton.setPadding(
-                        menuItemButton.getPaddingLeft(),
-                        menuItemButton.getPaddingTop(),
-                        2 * menuItemButton.getPaddingRight(),
-                        menuItemButton.getPaddingBottom());
+            stopDismissAnimation();
+            preparePopupContent();
+            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y);
+            growFadeInFromBottom();
+        }
+
+        /**
+         * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
+         */
+        public void dismiss() {
+            if (!isShowing()) {
+                return;
             }
 
-            menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-            int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
-            if (menuItemButtonWidth <= availableWidth) {
-                menuItemButton.setTag(menuItem);
-                menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
-                mMenuItemButtonsContainer.addView(menuItemButton);
-                menuItemButton.getLayoutParams().width = menuItemButtonWidth;
-                availableWidth -= menuItemButtonWidth;
-                remainingMenuItems.pop();
-            } else {
-                // The "open overflow" button launches the vertical overflow from the
-                // floating toolbar.
-                createOpenOverflowButtonIfNotExists();
-                mMenuItemButtonsContainer.addView(mOpenOverflowButton);
-                break;
+            mDismissAnimating = true;
+            shrinkFadeOutFromBottom();
+            setZeroTouchableSurface();
+        }
+
+        /**
+         * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
+         */
+        public boolean isShowing() {
+            return mPopupWindow.isShowing() && !mDismissAnimating;
+        }
+
+        /**
+         * Updates the coordinates of this popup.
+         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
+         */
+        public void updateCoordinates(int x, int y) {
+            if (mDismissAnimating) {
+                // Already being dismissed. Ignore.
+                return;
+            }
+
+            preparePopupContent();
+            mPopupWindow.update(x, y, getWidth(), getHeight());
+        }
+
+        /**
+         * Sets the direction in which the overflow will open. i.e. up or down.
+         *
+         * @param overflowDirection Either {@link #OVERFLOW_DIRECTION_UP}
+         *   or {@link #OVERFLOW_DIRECTION_DOWN}.
+         */
+        public void setOverflowDirection(int overflowDirection) {
+            mOverflowDirection = overflowDirection;
+            if (mOverflowPanel != null) {
+                mOverflowPanel.setOverflowDirection(mOverflowDirection);
             }
         }
-        mPopup.setContentView(mMenuItemButtonsContainer);
+
+        /**
+         * Returns the width of this popup.
+         */
+        public int getWidth() {
+            return mPopupWindow.getWidth();
+        }
+
+        /**
+         * Returns the height of this popup.
+         */
+        public int getHeight() {
+            return mPopupWindow.getHeight();
+        }
+
+        /**
+         * Returns the context this popup is running in.
+         */
+        public Context getContext() {
+            return mContentContainer.getContext();
+        }
+
+        /**
+         * Performs the "grow and fade in from the bottom" animation on the floating popup.
+         */
+        private void growFadeInFromBottom() {
+            mGrowFadeInFromBottomAnimation.start();
+        }
+
+        /**
+         * Performs the "shrink and fade out from bottom" animation on the floating popup.
+         */
+        private void shrinkFadeOutFromBottom() {
+            mShrinkFadeOutFromBottomAnimation.start();
+        }
+
+        private void stopDismissAnimation() {
+            mDismissAnimating = false;
+            mShrinkFadeOutFromBottomAnimation.cancel();
+        }
+
+        /**
+         * Opens the floating toolbar overflow.
+         * This method should not be called if menu items have not been laid out with
+         * {@link #layoutMenuItems(List, MenuItem.OnMenuItemClickListener, int)}.
+         *
+         * @throws IllegalStateException if called when menu items have not been laid out.
+         */
+        private void openOverflow() {
+            Preconditions.checkNotNull(mMainPanel);
+            Preconditions.checkNotNull(mOverflowPanel);
+
+            mMainPanel.fadeOut(true);
+            Size overflowPanelSize = mOverflowPanel.measure();
+            final int targetWidth = getOverflowWidth(mParent.getContext());
+            final int targetHeight = overflowPanelSize.getHeight();
+            final boolean morphUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
+            final int startWidth = mContentContainer.getWidth();
+            final int startHeight = mContentContainer.getHeight();
+            final float startY = mContentContainer.getY();
+            final float right = mContentContainer.getX() + mContentContainer.getWidth();
+            Animation widthAnimation = new Animation() {
+                @Override
+                protected void applyTransformation(float interpolatedTime, Transformation t) {
+                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
+                    int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
+                    params.width = startWidth + deltaWidth;
+                    mContentContainer.setLayoutParams(params);
+                    mContentContainer.setX(right - mContentContainer.getWidth());
+                }
+            };
+            Animation heightAnimation = new Animation() {
+                @Override
+                protected void applyTransformation(float interpolatedTime, Transformation t) {
+                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
+                    int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
+                    params.height = startHeight + deltaHeight;
+                    mContentContainer.setLayoutParams(params);
+                    if (morphUpwards) {
+                        float y = startY - (mContentContainer.getHeight() - startHeight);
+                        mContentContainer.setY(y);
+                    }
+                }
+            };
+            widthAnimation.setDuration(240);
+            heightAnimation.setDuration(180);
+            heightAnimation.setStartOffset(60);
+            AnimationSet animation = new AnimationSet(true);
+            animation.setAnimationListener(mOnOverflowOpened);
+            animation.addAnimation(widthAnimation);
+            animation.addAnimation(heightAnimation);
+            mContentContainer.startAnimation(animation);
+        }
+
+        /**
+         * Opens the floating toolbar overflow.
+         * This method should not be called if menu items have not been laid out with
+         * {@link #layoutMenuItems(java.util.List, MenuItem.OnMenuItemClickListener, int)}.
+         *
+         * @throws IllegalStateException
+         */
+        private void closeOverflow() {
+            Preconditions.checkNotNull(mMainPanel);
+            Preconditions.checkNotNull(mOverflowPanel);
+
+            mOverflowPanel.fadeOut(true);
+            Size mainPanelSize = mMainPanel.measure();
+            final int targetWidth = mainPanelSize.getWidth();
+            final int targetHeight = mainPanelSize.getHeight();
+            final int startWidth = mContentContainer.getWidth();
+            final int startHeight = mContentContainer.getHeight();
+            final float right = mContentContainer.getX() + mContentContainer.getWidth();
+            final float bottom = mContentContainer.getY() + mContentContainer.getHeight();
+            final boolean morphedUpwards = (mOverflowDirection == OVERFLOW_DIRECTION_UP);
+            Animation widthAnimation = new Animation() {
+                @Override
+                protected void applyTransformation(float interpolatedTime, Transformation t) {
+                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
+                    int deltaWidth = (int) (interpolatedTime * (targetWidth - startWidth));
+                    params.width = startWidth + deltaWidth;
+                    mContentContainer.setLayoutParams(params);
+                    mContentContainer.setX(right - mContentContainer.getWidth());
+                }
+            };
+            Animation heightAnimation = new Animation() {
+                @Override
+                protected void applyTransformation(float interpolatedTime, Transformation t) {
+                    ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
+                    int deltaHeight = (int) (interpolatedTime * (targetHeight - startHeight));
+                    params.height = startHeight + deltaHeight;
+                    mContentContainer.setLayoutParams(params);
+                    if (morphedUpwards) {
+                        mContentContainer.setY(bottom - mContentContainer.getHeight());
+                    }
+                }
+            };
+            widthAnimation.setDuration(150);
+            widthAnimation.setStartOffset(150);
+            heightAnimation.setDuration(210);
+            AnimationSet animation = new AnimationSet(true);
+            animation.setAnimationListener(mOnOverflowClosed);
+            animation.addAnimation(widthAnimation);
+            animation.addAnimation(heightAnimation);
+            mContentContainer.startAnimation(animation);
+        }
+
+        /**
+         * Prepares the content container for show and update calls.
+         */
+        private void preparePopupContent() {
+            // Do not call this method if main view panel has not been initialized.
+            Preconditions.checkNotNull(mMainPanel);
+
+            // If we're yet to show the popup, set the container visibility to zero.
+            // The "show" animation will make this visible.
+            if (!mPopupWindow.isShowing()) {
+                mContentContainer.setAlpha(0);
+            }
+
+            // Make sure panels are visible.
+            mMainPanel.fadeIn(false);
+            if (mOverflowPanel != null) {
+                mOverflowPanel.fadeIn(false);
+            }
+
+            // Make sure a panel is set as the content.
+            if (mContentContainer.getChildCount() == 0) {
+                mContentContainer.addView(mMainPanel.getView());
+            }
+
+            // Make sure the main panel is at the correct position.
+            if (mContentContainer.getChildAt(0) == mMainPanel.getView()) {
+                mContentContainer.setX(mPadding);
+                float y = mPadding;
+                if  (mOverflowDirection == OVERFLOW_DIRECTION_UP) {
+                    y = getHeight() - getEstimatedToolbarHeight(mParent.getContext()) - mPadding;
+                }
+                mContentContainer.setY(y);
+            }
+
+            setContentAreaAsTouchableSurface();
+        }
+
+        /**
+         * Sets the current content to be the main view panel.
+         */
+        private void setMainPanelAsContent() {
+            mContentContainer.removeAllViews();
+            Size mainPanelSize = mMainPanel.measure();
+            ViewGroup.LayoutParams params = mContentContainer.getLayoutParams();
+            params.width = mainPanelSize.getWidth();
+            params.height = mainPanelSize.getHeight();
+            mContentContainer.setLayoutParams(params);
+            mContentContainer.addView(mMainPanel.getView());
+        }
+
+        private void updatePopupSize() {
+            int width = 0;
+            int height = 0;
+            if (mMainPanel != null) {
+                Size mainPanelSize = mMainPanel.measure();
+                width = mainPanelSize.getWidth();
+                height = mainPanelSize.getHeight();
+            }
+            if (mOverflowPanel != null) {
+                Size overflowPanelSize = mOverflowPanel.measure();
+                width = Math.max(width, overflowPanelSize.getWidth());
+                height = Math.max(height, overflowPanelSize.getHeight());
+            }
+            mPopupWindow.setWidth(width + mPadding * 2);
+            mPopupWindow.setHeight(height + mPadding * 2);
+        }
+
+        /**
+         * Sets the touchable region of this popup to be zero. This means that all touch events on
+         * this popup will go through to the surface behind it.
+         */
+        private void setZeroTouchableSurface() {
+            mTouchableRegion.setEmpty();
+        }
+
+        /**
+         * Sets the touchable region of this popup to be the area occupied by its content.
+         */
+        private void setContentAreaAsTouchableSurface() {
+            if (!mPopupWindow.isShowing()) {
+                mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+            }
+            int width = mContentContainer.getMeasuredWidth();
+            int height = mContentContainer.getMeasuredHeight();
+            mTouchableRegion.set(
+                    (int) mContentContainer.getX(),
+                    (int) mContentContainer.getY(),
+                    (int) mContentContainer.getX() + width,
+                    (int) mContentContainer.getY() + height);
+        }
     }
 
     /**
-     * Creates and returns the button that opens the vertical overflow.
+     * A widget that holds the primary menu items in the floating toolbar.
      */
-    private void createOpenOverflowButtonIfNotExists() {
-        mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext)
-                .inflate(R.layout.floating_popup_open_overflow_button, null);
-        mOpenOverflowButton.setOnClickListener(
+    private static final class FloatingToolbarMainPanel {
+
+        private final Context mContext;
+        private final ViewGroup mContentView;
+        private final View.OnClickListener mMenuItemButtonOnClickListener =
                 new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        // Open the overflow.
+                        if (v.getTag() instanceof MenuItem) {
+                            if (mOnMenuItemClickListener != null) {
+                                mOnMenuItemClickListener.onMenuItemClick((MenuItem) v.getTag());
+                            }
+                        }
                     }
-                });
+                };
+        private final ViewFader viewFader;
+        private final Runnable mOpenOverflow;
+
+        private View mOpenOverflowButton;
+        private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
+
+        /**
+         * Initializes a floating toolbar popup main view panel.
+         *
+         * @param context
+         * @param openOverflow  The code that opens the toolbar popup overflow.
+         */
+        public FloatingToolbarMainPanel(Context context, Runnable openOverflow) {
+            mContext = Preconditions.checkNotNull(context);
+            mContentView = new LinearLayout(context);
+            viewFader = new ViewFader(mContentView);
+            mOpenOverflow = Preconditions.checkNotNull(openOverflow);
+        }
+
+        /**
+         * Fits as many menu items in the main panel and returns a list of the menu items that
+         * were not fit in.
+         *
+         * @return The menu items that are not included in this main panel.
+         */
+        public List<MenuItem> layoutMenuItems(List<MenuItem> menuItems, int suggestedWidth) {
+            final int toolbarWidth = getAdjustedToolbarWidth(mContext, suggestedWidth)
+                    // Reserve space for the "open overflow" button.
+                    - getEstimatedOpenOverflowButtonWidth(mContext);
+
+            int availableWidth = toolbarWidth;
+            final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
+
+            mContentView.removeAllViews();
+
+            boolean isFirstItem = true;
+            while (!remainingMenuItems.isEmpty()) {
+                final MenuItem menuItem = remainingMenuItems.peek();
+                Button menuItemButton = createMenuItemButton(mContext, menuItem);
+
+                // Adding additional left padding for the first button to even out button spacing.
+                if (isFirstItem) {
+                    menuItemButton.setPadding(
+                            2 * menuItemButton.getPaddingLeft(),
+                            menuItemButton.getPaddingTop(),
+                            menuItemButton.getPaddingRight(),
+                            menuItemButton.getPaddingBottom());
+                    isFirstItem = false;
+                }
+
+                // Adding additional right padding for the last button to even out button spacing.
+                if (remainingMenuItems.size() == 1) {
+                    menuItemButton.setPadding(
+                            menuItemButton.getPaddingLeft(),
+                            menuItemButton.getPaddingTop(),
+                            2 * menuItemButton.getPaddingRight(),
+                            menuItemButton.getPaddingBottom());
+                }
+
+                menuItemButton.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+                int menuItemButtonWidth = Math.min(menuItemButton.getMeasuredWidth(), toolbarWidth);
+                if (menuItemButtonWidth <= availableWidth) {
+                    menuItemButton.setTag(menuItem);
+                    menuItemButton.setOnClickListener(mMenuItemButtonOnClickListener);
+                    mContentView.addView(menuItemButton);
+                    ViewGroup.LayoutParams params = menuItemButton.getLayoutParams();
+                    params.width = menuItemButtonWidth;
+                    menuItemButton.setLayoutParams(params);
+                    availableWidth -= menuItemButtonWidth;
+                    remainingMenuItems.pop();
+                } else {
+                    if (mOpenOverflowButton == null) {
+                        mOpenOverflowButton = (ImageButton) LayoutInflater.from(mContext)
+                                .inflate(R.layout.floating_popup_open_overflow_button, null);
+                        mOpenOverflowButton.setOnClickListener(new View.OnClickListener() {
+                            @Override
+                            public void onClick(View v) {
+                                if (mOpenOverflowButton != null) {
+                                    mOpenOverflow.run();
+                                }
+                            }
+                        });
+                    }
+                    mContentView.addView(mOpenOverflowButton);
+                    break;
+                }
+            }
+            return remainingMenuItems;
+        }
+
+        public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
+            mOnMenuItemClickListener = listener;
+        }
+
+        public View getView() {
+            return mContentView;
+        }
+
+        public void fadeIn(boolean animate) {
+            viewFader.fadeIn(animate);
+        }
+
+        public void fadeOut(boolean animate) {
+            viewFader.fadeOut(animate);
+        }
+
+        /**
+         * Returns how big this panel's view should be.
+         * This method should only be called when the view has not been attached to a parent
+         * otherwise it will throw an illegal state.
+         */
+        public Size measure() throws IllegalStateException {
+            Preconditions.checkState(mContentView.getParent() == null);
+            mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+            return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
+        }
     }
 
+
     /**
-     * Creates and returns a floating toolbar menu buttons container.
+     * A widget that holds the overflow items in the floating toolbar.
      */
-    private static ViewGroup createMenuButtonsContainer(Context context) {
-        return (ViewGroup) LayoutInflater.from(context)
-                .inflate(R.layout.floating_popup_container, null);
+    private static final class FloatingToolbarOverflowPanel {
+
+        private final LinearLayout mContentView;
+        private final ViewGroup mBackButtonContainer;
+        private final View mBackButton;
+        private final ListView mListView;
+        private final ViewFader mViewFader;
+        private final Runnable mCloseOverflow;
+
+        private MenuItem.OnMenuItemClickListener mOnMenuItemClickListener;
+
+        /**
+         * Initializes a floating toolbar popup overflow view panel.
+         *
+         * @param context
+         * @param closeOverflow  The code that closes the toolbar popup's overflow.
+         */
+        public FloatingToolbarOverflowPanel(Context context, Runnable closeOverflow) {
+            mCloseOverflow = Preconditions.checkNotNull(closeOverflow);
+
+            mContentView = new LinearLayout(context);
+            mContentView.setOrientation(LinearLayout.VERTICAL);
+            mViewFader = new ViewFader(mContentView);
+
+            mBackButton = LayoutInflater.from(context)
+                    .inflate(R.layout.floating_popup_close_overflow_button, null);
+            mBackButton.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mCloseOverflow.run();
+                }
+            });
+            mBackButtonContainer = new LinearLayout(context);
+            mBackButtonContainer.addView(mBackButton);
+
+            mListView = createOverflowListView(context);
+            mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+                @Override
+                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                    MenuItem menuItem = (MenuItem) mListView.getAdapter().getItem(position);
+                    if (mOnMenuItemClickListener != null) {
+                        mOnMenuItemClickListener.onMenuItemClick(menuItem);
+                    }
+                }
+            });
+
+            mContentView.addView(mListView);
+            mContentView.addView(mBackButtonContainer);
+        }
+
+        /**
+         * Sets the menu items to be displayed in the overflow.
+         */
+        public void setMenuItems(List<MenuItem> menuItems) {
+            ArrayAdapter overflowListViewAdapter = (ArrayAdapter) mListView.getAdapter();
+            overflowListViewAdapter.clear();
+            overflowListViewAdapter.addAll(menuItems);
+            setListViewHeight();
+        }
+
+        public void setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener listener) {
+            mOnMenuItemClickListener = listener;
+        }
+
+        /**
+         * Notifies the overflow of the current direction in which the overflow will be opened.
+         *
+         * @param overflowDirection  {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_UP}
+         *   or {@link FloatingToolbarPopup#OVERFLOW_DIRECTION_DOWN}.
+         */
+        public void setOverflowDirection(int overflowDirection) {
+            mContentView.removeView(mBackButtonContainer);
+            int index = (overflowDirection == FloatingToolbarPopup.OVERFLOW_DIRECTION_UP)? 1 : 0;
+            mContentView.addView(mBackButtonContainer, index);
+        }
+
+        /**
+         * Returns the content view of the overflow.
+         */
+        public View getView() {
+            return mContentView;
+        }
+
+        public void fadeIn(boolean animate) {
+            mViewFader.fadeIn(animate);
+        }
+
+        public void fadeOut(boolean animate) {
+            mViewFader.fadeOut(animate);
+        }
+
+        /**
+         * Returns how big this panel's view should be.
+         * This method should only be called when the view has not been attached to a parent.
+         *
+         * @throws IllegalStateException
+         */
+        public Size measure() {
+            Preconditions.checkState(mContentView.getParent() == null);
+            mContentView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+            return new Size(mContentView.getMeasuredWidth(), mContentView.getMeasuredHeight());
+        }
+
+        private void setListViewHeight() {
+            int itemHeight = getEstimatedToolbarHeight(mContentView.getContext());
+            int height = mListView.getAdapter().getCount() * itemHeight;
+            int maxHeight = mContentView.getContext().getResources().
+                    getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
+            ViewGroup.LayoutParams params = mListView.getLayoutParams();
+            params.height = Math.min(height, maxHeight);
+            mListView.setLayoutParams(params);
+        }
+
+        private static ListView createOverflowListView(final Context context) {
+            final ListView overflowListView = new ListView(context);
+            overflowListView.setLayoutParams(new ViewGroup.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
+            overflowListView.setDivider(null);
+            overflowListView.setDividerHeight(0);
+            final ArrayAdapter overflowListViewAdapter =
+                    new ArrayAdapter<MenuItem>(context, 0) {
+                        @Override
+                        public View getView(int position, View convertView, ViewGroup parent) {
+                            TextView menuButton;
+                            if (convertView != null) {
+                                menuButton = (TextView) convertView;
+                            } else {
+                                menuButton = createOverflowMenuItemButton(context);
+                            }
+                            MenuItem menuItem = getItem(position);
+                            menuButton.setText(menuItem.getTitle());
+                            menuButton.setContentDescription(menuItem.getTitle());
+                            return menuButton;
+                        }
+                    };
+            overflowListView.setAdapter(overflowListViewAdapter);
+            return overflowListView;
+        }
     }
 
+
+    /**
+     * A helper for fading in or out a view.
+     */
+    private static final class ViewFader {
+
+        private static final int FADE_OUT_DURATION = 250;
+        private static final int FADE_IN_DURATION = 150;
+
+        private final View mView;
+        private final ObjectAnimator mFadeOutAnimation;
+        private final ObjectAnimator mFadeInAnimation;
+
+        private ViewFader(View view) {
+            mView = Preconditions.checkNotNull(view);
+            mFadeOutAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0)
+                    .setDuration(FADE_OUT_DURATION);
+            mFadeInAnimation = ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1)
+                    .setDuration(FADE_IN_DURATION);
+        }
+
+        public void fadeIn(boolean animate) {
+            if (animate) {
+                mFadeInAnimation.start();
+            } else {
+                mView.setAlpha(1);
+            }
+        }
+
+        public void fadeOut(boolean animate) {
+            if (animate) {
+                mFadeOutAnimation.start();
+            } else {
+                mView.setAlpha(0);
+            }
+        }
+    }
+
+
     /**
      * Creates and returns a menu button for the specified menu item.
      */
@@ -346,9 +1020,70 @@
         return menuItemButton;
     }
 
-    private static int getMinimumOverflowHeight(Context context) {
-        return context.getResources().
-                getDimensionPixelSize(R.dimen.floating_toolbar_minimum_overflow_height);
+    /**
+     * Creates and returns a styled floating toolbar overflow list view item.
+     */
+    private static TextView createOverflowMenuItemButton(Context context) {
+        return (TextView) LayoutInflater.from(context)
+                .inflate(R.layout.floating_popup_overflow_list_item, null);
+    }
+
+    private static ViewGroup createContentContainer(Context context) {
+        return (ViewGroup) LayoutInflater.from(context)
+                .inflate(R.layout.floating_popup_container, null);
+    }
+
+    private static PopupWindow createPopupWindow(View content) {
+        ViewGroup popupContentHolder = new LinearLayout(content.getContext());
+        PopupWindow popupWindow = new PopupWindow(popupContentHolder);
+        popupWindow.setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL);
+        popupWindow.setAnimationStyle(0);
+        popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        content.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+        popupContentHolder.addView(content);
+        return popupWindow;
+    }
+
+    /**
+     * Creates a "grow and fade in from the bottom" animation for the specified view.
+     *
+     * @param view  The view to animate
+     */
+    private static AnimatorSet createGrowFadeInFromBottom(View view) {
+        AnimatorSet growFadeInFromBottomAnimation =  new AnimatorSet();
+        growFadeInFromBottomAnimation.playTogether(
+                ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125),
+                ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125),
+                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75));
+        growFadeInFromBottomAnimation.setStartDelay(50);
+        return growFadeInFromBottomAnimation;
+    }
+
+    /**
+     * Creates a "shrink and fade out from bottom" animation for the specified view.
+     *
+     * @param view  The view to animate
+     * @param listener  The animation listener
+     */
+    private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
+            View view, Animator.AnimatorListener listener) {
+        AnimatorSet shrinkFadeOutFromBottomAnimation =  new AnimatorSet();
+        shrinkFadeOutFromBottomAnimation.playTogether(
+                ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
+                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
+        shrinkFadeOutFromBottomAnimation.setStartDelay(150);
+        shrinkFadeOutFromBottomAnimation.addListener(listener);
+        return shrinkFadeOutFromBottomAnimation;
+    }
+
+    private static int getOverflowWidth(Context context) {
+        return context.getResources()
+                .getDimensionPixelSize(R.dimen.floating_toolbar_overflow_width);
+    }
+
+    private static int getEstimatedToolbarHeight(Context context) {
+        return context.getResources().getDimensionPixelSize(R.dimen.floating_toolbar_height);
     }
 
     private static int getEstimatedOpenOverflowButtonWidth(Context context) {
@@ -367,230 +1102,26 @@
     /**
      * Returns the device's screen width.
      */
-    public static int getScreenWidth(Context context) {
+    private static int getScreenWidth(Context context) {
         return context.getResources().getDisplayMetrics().widthPixels;
     }
 
     /**
      * Returns the device's screen height.
      */
-    public static int getScreenHeight(Context context) {
+    private static int getScreenHeight(Context context) {
         return context.getResources().getDisplayMetrics().heightPixels;
     }
 
-
     /**
-     * A popup window used by the floating toolbar.
+     * Returns value, restricted to the range min->max (inclusive).
+     * If maximum is less than minimum, the result is undefined.
+     *
+     * @param value  The value to clamp.
+     * @param minimum  The minimum value in the range.
+     * @param maximum  The maximum value in the range. Must not be less than minimum.
      */
-    private static final class FloatingToolbarPopup {
-
-        private final View mParent;
-        private final PopupWindow mPopupWindow;
-        private final ViewGroup mContentContainer;
-        private final Animator.AnimatorListener mOnDismissEnd =
-                new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator animation) {
-                        mPopupWindow.dismiss();
-                        mDismissAnimating = false;
-                    }
-                };
-        private final AnimatorSet mGrowFadeInFromBottomAnimation;
-        private final AnimatorSet mShrinkFadeOutFromBottomAnimation;
-
-        private boolean mDismissAnimating;
-
-        /**
-         * Initializes a new floating bar popup.
-         *
-         * @param parent  A parent view to get the {@link View#getWindowToken()} token from.
-         */
-        public FloatingToolbarPopup(View parent) {
-            mParent = Preconditions.checkNotNull(parent);
-            mContentContainer = createContentContainer(parent.getContext());
-            mPopupWindow = createPopupWindow(mContentContainer);
-            mGrowFadeInFromBottomAnimation = createGrowFadeInFromBottom(mContentContainer);
-            mShrinkFadeOutFromBottomAnimation =
-                    createShrinkFadeOutFromBottomAnimation(mContentContainer, mOnDismissEnd);
-        }
-
-        /**
-         * Shows this popup at the specified coordinates.
-         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
-         * If this popup is already showing, this will be a no-op.
-         */
-        public void show(int x, int y) {
-            if (isShowing()) {
-                updateCoordinates(x, y);
-                return;
-            }
-
-            mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, 0, 0);
-            positionOnScreen(x, y);
-            growFadeInFromBottom();
-
-            mDismissAnimating = false;
-        }
-
-        /**
-         * Gets rid of this popup. If the popup isn't currently showing, this will be a no-op.
-         */
-        public void dismiss() {
-            if (!isShowing()) {
-                return;
-            }
-
-            if (mDismissAnimating) {
-                // This window is already dismissing. Don't restart the animation.
-                return;
-            }
-            mDismissAnimating = true;
-            shrinkFadeOutFromBottom();
-        }
-
-        /**
-         * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
-         */
-        public boolean isShowing() {
-            return mPopupWindow.isShowing() && !mDismissAnimating;
-        }
-
-        /**
-         * Updates the coordinates of this popup.
-         * The specified coordinates may be adjusted to make sure the popup is entirely on-screen.
-         */
-        public void updateCoordinates(int x, int y) {
-            if (isShowing()) {
-                positionOnScreen(x, y);
-            }
-        }
-
-        /**
-         * Sets the content of this popup.
-         */
-        public void setContentView(View view) {
-            Preconditions.checkNotNull(view);
-            mContentContainer.removeAllViews();
-            mContentContainer.addView(view);
-        }
-
-        /**
-         * Returns the width of this popup.
-         */
-        public int getWidth() {
-            return mContentContainer.getWidth();
-        }
-
-        /**
-         * Returns the height of this popup.
-         */
-        public int getHeight() {
-            return mContentContainer.getHeight();
-        }
-
-        /**
-         * Returns the context this popup is running in.
-         */
-        public Context getContext() {
-            return mContentContainer.getContext();
-        }
-
-        private void positionOnScreen(int x, int y) {
-            if (getWidth() == 0) {
-                // content size is yet to be measured.
-                mContentContainer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-            }
-            x = clamp(x, 0, getScreenWidth(getContext()) - getWidth());
-            y = clamp(y, 0, getScreenHeight(getContext()) - getHeight());
-
-            // Position the view w.r.t. the window.
-            mContentContainer.setX(x);
-            mContentContainer.setY(y);
-        }
-
-        /**
-         * Performs the "grow and fade in from the bottom" animation on the floating popup.
-         */
-        private void growFadeInFromBottom() {
-            setPivot();
-            mGrowFadeInFromBottomAnimation.start();
-        }
-
-        /**
-         * Performs the "shrink and fade out from bottom" animation on the floating popup.
-         */
-        private void shrinkFadeOutFromBottom() {
-            setPivot();
-            mShrinkFadeOutFromBottomAnimation.start();
-        }
-
-        /**
-         * Sets the popup content container's pivot.
-         */
-        private void setPivot() {
-            mContentContainer.setPivotX(mContentContainer.getMeasuredWidth() / 2);
-            mContentContainer.setPivotY(mContentContainer.getMeasuredHeight());
-        }
-
-        private static ViewGroup createContentContainer(Context context) {
-            return (ViewGroup) LayoutInflater.from(context)
-                    .inflate(R.layout.floating_popup_container, null);
-        }
-
-        private static PopupWindow createPopupWindow(View content) {
-            ViewGroup popupContentHolder = new LinearLayout(content.getContext());
-            PopupWindow popupWindow = new PopupWindow(popupContentHolder);
-            popupWindow.setAnimationStyle(0);
-            popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
-            popupWindow.setWidth(getScreenWidth(content.getContext()));
-            popupWindow.setHeight(getScreenHeight(content.getContext()));
-            content.setLayoutParams(new ViewGroup.LayoutParams(
-                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
-            popupContentHolder.addView(content);
-            return popupWindow;
-        }
-
-        /**
-         * Creates a "grow and fade in from the bottom" animation for the specified view.
-         *
-         * @param view  The view to animate
-         */
-        private static AnimatorSet createGrowFadeInFromBottom(View view) {
-            AnimatorSet growFadeInFromBottomAnimation =  new AnimatorSet();
-            growFadeInFromBottomAnimation.playTogether(
-                    ObjectAnimator.ofFloat(view, View.SCALE_X, 0.5f, 1).setDuration(125),
-                    ObjectAnimator.ofFloat(view, View.SCALE_Y, 0.5f, 1).setDuration(125),
-                    ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(75));
-            return growFadeInFromBottomAnimation;
-        }
-
-        /**
-         * Creates a "shrink and fade out from bottom" animation for the specified view.
-         *
-         * @param view  The view to animate
-         * @param listener  The animation listener
-         */
-        private static AnimatorSet createShrinkFadeOutFromBottomAnimation(
-                View view, Animator.AnimatorListener listener) {
-            AnimatorSet shrinkFadeOutFromBottomAnimation =  new AnimatorSet();
-            shrinkFadeOutFromBottomAnimation.playTogether(
-                    ObjectAnimator.ofFloat(view, View.SCALE_Y, 1, 0.5f).setDuration(125),
-                    ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(75));
-            shrinkFadeOutFromBottomAnimation.setStartDelay(150);
-            shrinkFadeOutFromBottomAnimation.addListener(listener);
-            return shrinkFadeOutFromBottomAnimation;
-        }
-
-        /**
-         * Returns value, restricted to the range min->max (inclusive).
-         * If maximum is less than minimum, the result is undefined.
-         *
-         * @param value  The value to clamp.
-         * @param minimum  The minimum value in the range.
-         * @param maximum  The maximum value in the range. Must not be less than minimum.
-         */
-        private static int clamp(int value, int minimum, int maximum) {
-            return Math.max(minimum, Math.min(value, maximum));
-        }
+    private static int clamp(int value, int minimum, int maximum) {
+        return Math.max(minimum, Math.min(value, maximum));
     }
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 90821dc..2967876 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -449,29 +449,29 @@
      * @param disable Disables lock screen when true
      */
     public void setLockScreenDisabled(boolean disable) {
-        setBoolean(DISABLE_LOCKSCREEN_KEY, disable, getCurrentOrCallingUserId());
+        setLockScreenDisabled(disable, getCurrentOrCallingUserId());
     }
 
     /**
-     * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
-     * show LockScreen or go straight to the home screen.
+     * Disable showing lock screen at all for a given user.
+     * This is only meaningful if pattern, pin or password are not set.
      *
-     * @return true if lock screen is can be disabled
+     * @param disable Disables lock screen when true
+     * @param userId User ID of the user this has effect on
+     */
+    public void setLockScreenDisabled(boolean disable, int userId) {
+        setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
+    }
+
+    /**
+     * Determine if LockScreen is disabled for the current user. This is used to decide whether
+     * LockScreen is shown after reboot or after screen timeout / short press on power.
+     *
+     * @return true if lock screen is disabled
      */
     public boolean isLockScreenDisabled() {
-        if (!isSecure() && getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId())) {
-            // Check if the number of switchable users forces the lockscreen.
-            final List<UserInfo> users = UserManager.get(mContext).getUsers(true);
-            final int userCount = users.size();
-            int switchableUsers = 0;
-            for (int i = 0; i < userCount; i++) {
-                if (users.get(i).supportsSwitchTo()) {
-                    switchableUsers++;
-                }
-            }
-            return switchableUsers < 2;
-        }
-        return false;
+        return !isSecure() &&
+                getBoolean(DISABLE_LOCKSCREEN_KEY, false, getCurrentOrCallingUserId());
     }
 
     /**
diff --git a/core/java/com/android/server/backup/PreferredActivityBackupHelper.java b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
new file mode 100644
index 0000000..6ac0d89
--- /dev/null
+++ b/core/java/com/android/server/backup/PreferredActivityBackupHelper.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.backup;
+
+import android.app.AppGlobals;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupHelper;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+import com.android.org.bouncycastle.util.Arrays;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class PreferredActivityBackupHelper implements BackupHelper {
+    private static final String TAG = "PreferredBackup";
+    private static final boolean DEBUG = true;
+
+    // current schema of the backup state blob
+    private static final int STATE_VERSION = 1;
+
+    // key under which the preferred-activity state blob is committed to backup
+    private static final String KEY_PREFERRED = "preferred-activity";
+
+    final Context mContext;
+
+    public PreferredActivityBackupHelper(Context context) {
+        mContext = context;
+    }
+
+    // The fds passed here are shared among all helpers, so we mustn't close them
+    private void writeState(ParcelFileDescriptor stateFile, byte[] payload) {
+        try {
+            FileOutputStream fos = new FileOutputStream(stateFile.getFileDescriptor());
+
+            // We explicitly don't close 'out' because we must not close the backing fd.
+            // The FileOutputStream will not close it implicitly.
+            @SuppressWarnings("resource")
+            DataOutputStream out = new DataOutputStream(fos);
+
+            out.writeInt(STATE_VERSION);
+            if (payload == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(payload.length);
+                out.write(payload);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to write updated state", e);
+        }
+    }
+
+    private byte[] readState(ParcelFileDescriptor oldStateFd) {
+        FileInputStream fis = new FileInputStream(oldStateFd.getFileDescriptor());
+        BufferedInputStream bis = new BufferedInputStream(fis);
+
+        @SuppressWarnings("resource")
+        DataInputStream in = new DataInputStream(bis);
+
+        byte[] oldState = null;
+        try {
+            int version = in.readInt();
+            if (version == STATE_VERSION) {
+                int size = in.readInt();
+                if (size > 0) {
+                    if (size > 200*1024) {
+                        Slog.w(TAG, "Suspiciously large state blog; ignoring.  N=" + size);
+                    } else {
+                        // size looks okay; make the return buffer and fill it
+                        oldState = new byte[size];
+                        in.read(oldState);
+                    }
+                }
+            } else {
+                Slog.w(TAG, "Prior state from unrecognized version " + version);
+            }
+        } catch (EOFException e) {
+            // Empty file is expected on first backup,  so carry on. If the state
+            // is truncated we just treat it the same way.
+            oldState = null;
+        } catch (Exception e) {
+            Slog.w(TAG, "Error examing prior backup state " + e.getMessage());
+            oldState = null;
+        }
+
+        return oldState;
+    }
+
+    @Override
+    public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) {
+        byte[] payload = null;
+        try {
+            byte[] oldPayload = readState(oldState);
+
+            IPackageManager pm = AppGlobals.getPackageManager();
+            byte[] newPayload = pm.getPreferredActivityBackup(UserHandle.USER_OWNER);
+            if (!Arrays.areEqual(oldPayload, newPayload)) {
+                if (DEBUG) {
+                    Slog.i(TAG, "State has changed => writing new preferred app payload");
+                }
+                data.writeEntityHeader(KEY_PREFERRED, newPayload.length);
+                data.writeEntityData(newPayload, newPayload.length);
+            } else {
+                if (DEBUG) {
+                    Slog.i(TAG, "No change to state => not writing to wire");
+                }
+            }
+
+            // Always need to re-record the state, even if nothing changed
+            payload = newPayload;
+        } catch (Exception e) {
+            // On failures we'll wind up committing a zero-size state payload.  This is
+            // a forward-safe situation because we know we commit the entire new payload
+            // on prior-state mismatch.
+            Slog.w(TAG, "Unable to record preferred activities", e);
+        } finally {
+            writeState(newState, payload);
+        }
+    }
+
+    @Override
+    public void restoreEntity(BackupDataInputStream data) {
+        IPackageManager pm = AppGlobals.getPackageManager();
+        try {
+            byte[] payload = new byte[data.size()];
+            data.read(payload);
+            if (DEBUG) {
+                Slog.i(TAG, "Restoring preferred activities; size=" + payload.length);
+            }
+            pm.restorePreferredActivities(payload, UserHandle.USER_OWNER);
+        } catch (Exception e) {
+            Slog.e(TAG, "Exception reading restore data", e);
+        }
+    }
+
+    @Override
+    public void writeNewStateDescription(ParcelFileDescriptor newState) {
+        writeState(newState, null);
+    }
+
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 037fd66..19d9e29 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -16,7 +16,6 @@
 
 package com.android.server.backup;
 
-
 import android.app.ActivityManagerNative;
 import android.app.IWallpaperManager;
 import android.app.backup.BackupDataInput;
@@ -43,6 +42,13 @@
 public class SystemBackupAgent extends BackupAgentHelper {
     private static final String TAG = "SystemBackupAgent";
 
+    // Names of the helper tags within the dataset.  Changing one of these names will
+    // break the ability to restore from datasets that predate the change.
+    private static final String WALLPAPER_HELPER = "wallpaper";
+    private static final String RECENTS_HELPER = "recents";
+    private static final String SYNC_SETTINGS_HELPER = "account_sync_settings";
+    private static final String PREFERRED_HELPER = "preferred_activities";
+
     // These paths must match what the WallpaperManagerService uses.  The leaf *_FILENAME
     // are also used in the full-backup file format, so must not change unless steps are
     // taken to support the legacy backed-up datasets.
@@ -84,10 +90,10 @@
                 Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
             }
         }
-        addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
-        addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
-        addHelper("account_sync_settings",
-                new AccountSyncSettingsBackupHelper(SystemBackupAgent.this));
+        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
+        addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
+        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
+        addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(this));
 
         super.onBackup(oldState, data, newState);
     }
@@ -113,15 +119,15 @@
     public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
             throws IOException {
         // On restore, we also support a previous data schema "system_files"
-        addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
+        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
                 new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
-        addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
+        addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
-        addHelper("recents", new RecentsBackupHelper(SystemBackupAgent.this));
-        addHelper("account_sync_settings",
-                new AccountSyncSettingsBackupHelper(SystemBackupAgent.this));
+        addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
+        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
+        addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper(this));
 
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 84568e4..cd117eb1 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -151,7 +151,6 @@
     android_util_FileObserver.cpp \
     android/opengl/poly_clip.cpp.arm \
     android/opengl/util.cpp \
-    android_server_FingerprintManager.cpp \
     android_server_NetworkManagementSocketTagger.cpp \
     android_server_Watchdog.cpp \
     android_ddm_DdmHandleNativeHeap.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index a4c91b3..88f0697 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -552,6 +552,7 @@
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
+    char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
     char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
@@ -560,6 +561,10 @@
     char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
     char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
     char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
+    char dex2oat_isa_variant_key[PROPERTY_KEY_MAX];
+    char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX];
+    char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
+    char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX];
     char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
     char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
     char extraOptsBuf[PROPERTY_VALUE_MAX];
@@ -738,6 +743,43 @@
     parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
     parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
                         "-Ximage-compiler-option");
+
+    // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to
+    // pass the instruction-set-features/variant as an image-compiler-option.
+    // TODO: Find a better way for the instruction-set.
+#if defined(__arm__)
+    constexpr const char* instruction_set = "arm";
+#elif defined(__aarch64__)
+    constexpr const char* instruction_set = "arm64";
+#elif defined(__mips__) && !defined(__LP64__)
+    constexpr const char* instruction_set = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+    constexpr const char* instruction_set = "mips64";
+#elif defined(__i386__)
+    constexpr const char* instruction_set = "x86";
+#elif defined(__x86_64__)
+    constexpr const char* instruction_set = "x86_64";
+#else
+    constexpr const char* instruction_set = "unknown";
+#endif
+    // Note: it is OK to reuse the buffer, as the values are exactly the same between
+    //       * compiler-option, used for runtime compilation (DexClassLoader)
+    //       * image-compiler-option, used for boot-image compilation on device
+
+    // Copy the variant.
+    sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
+    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
+                        "--instruction-set-variant=", "-Ximage-compiler-option");
+    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
+                        "--instruction-set-variant=", "-Xcompiler-option");
+    // Copy the features.
+    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
+    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
+                        "--instruction-set-features=", "-Ximage-compiler-option");
+    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
+                        "--instruction-set-features=", "-Xcompiler-option");
+
+
     property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
     parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
 
@@ -829,6 +871,10 @@
     snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
     addOption(cpuAbiListBuf);
 
+    // Dalvik-cache pruning counter.
+    parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
+                       "-Xzygote-max-boot-retry=");
+
     initArgs.version = JNI_VERSION_1_4;
     initArgs.options = mOptions.editArray();
     initArgs.nOptions = mOptions.size();
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 526885f..4c4a39d 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -543,6 +543,11 @@
     return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
 }
 
+jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
+    SkMemoryStream  stream(data, size);
+    return doDecode(env, &stream, NULL, NULL);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static JNINativeMethod gMethods[] = {
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index a54da43..22a955f 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -21,4 +21,6 @@
 
 jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format);
 
+jobject decodeBitmap(JNIEnv* env, void* data, size_t size);
+
 #endif  // _ANDROID_GRAPHICS_BITMAP_FACTORY_H_
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 4b43de3..4906f59 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -23,6 +23,7 @@
 #include "GraphicsJNI.h"
 #include "core_jni_helpers.h"
 #include <ScopedUtfChars.h>
+#include <ScopedStringChars.h>
 
 #include "SkBlurDrawLooper.h"
 #include "SkColorFilter.h"
@@ -41,6 +42,8 @@
 #include "Paint.h"
 #include "TypefaceImpl.h"
 
+#include <vector>
+
 // temporary for debugging
 #include <Caches.h>
 #include <utils/Log.h>
@@ -574,7 +577,8 @@
 
         Layout layout;
         TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, index, count, textLength);
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + index, 0, count,
+                count);
         result = layout.getAdvance();
         env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
         return result;
@@ -972,6 +976,68 @@
                                       JNI_ABORT);
     }
 
+    static jboolean layoutContainsNotdef(const Layout& layout) {
+        for (size_t i = 0; i < layout.nGlyphs(); i++) {
+            if (layout.getGlyphId(i) == 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    static jboolean hasGlyphVariation(const Paint* paint, TypefaceImpl* typeface, jint bidiFlags,
+            const jchar* chars, size_t size) {
+        // TODO: query font for whether character has variation selector; requires a corresponding
+        // function in Minikin.
+        return false;
+    }
+
+    static jboolean hasGlyph(JNIEnv *env, jclass, jlong paintHandle, jlong typefaceHandle,
+            jint bidiFlags, jstring string) {
+        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
+        ScopedStringChars str(env, string);
+
+        /* start by rejecting variation selectors (not supported yet) */
+        size_t nChars = 0;
+        for (size_t i = 0; i < str.size(); i++) {
+            jchar c = str[i];
+            if (0xDC00 <= c && c <= 0xDFFF) {
+                // invalid UTF-16, unpaired trailing surrogate
+                return false;
+            } else if (0xD800 <= c && c <= 0xDBFF) {
+                if (i + 1 == str.size()) {
+                    // invalid UTF-16, unpaired leading surrogate at end of string
+                    return false;
+                }
+                i++;
+                jchar c2 = str[i];
+                if (!(0xDC00 <= c2 && c2 <= 0xDFFF)) {
+                    // invalid UTF-16, unpaired leading surrogate
+                    return false;
+                }
+                // UTF-16 encoding of range U+E0100..U+E01EF is DB40 DD00 .. DB40 DDEF
+                if (c == 0xDB40 && 0xDD00 <= c2 && c2 <= 0xDDEF) {
+                    return hasGlyphVariation(paint, typeface, bidiFlags, str.get(), str.size());
+                }
+            } else if (0xFE00 <= c && c <= 0xFE0F) {
+                return hasGlyphVariation(paint, typeface, bidiFlags, str.get(), str.size());
+            }
+            nChars++;
+        }
+        Layout layout;
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, str.get(), 0, str.size(),
+                str.size());
+        size_t nGlyphs = layout.nGlyphs();
+        if (nGlyphs != 1 && nChars > 1) {
+            // multiple-character input, and was not a ligature
+            // TODO: handle ZWJ/ZWNJ characters specially so we can detect certain ligatures
+            // in joining scripts, such as Arabic and Mongolian.
+            return false;
+        }
+        return nGlyphs > 0 && !layoutContainsNotdef(layout);
+    }
+
 };
 
 static JNINativeMethod methods[] = {
@@ -1057,6 +1123,7 @@
                                         (void*) PaintGlue::getStringBounds },
     {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
                                     (void*) PaintGlue::getCharArrayBounds },
+    {"native_hasGlyph",           "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
 
     {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
     {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index b092e44..e0cbc9e 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -18,7 +18,7 @@
 #include "core_jni_helpers.h"
 
 #include "GraphicsJNI.h"
-#include <ScopedPrimitiveArray.h>
+#include "ScopedPrimitiveArray.h"
 #include "SkTypeface.h"
 #include "TypefaceImpl.h"
 #include <android_runtime/android_util_AssetManager.h>
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 655b400..e9f18a6 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -5,6 +5,7 @@
 #include <utils/Log.h>
 #include <ScopedUtfChars.h>
 
+#include "BitmapFactory.h"
 #include "EmojiFactory.h"
 #include "GraphicsJNI.h"
 #include <nativehelper/JNIHelp.h>
@@ -164,14 +165,7 @@
     return NULL;
   }
 
-  SkBitmap *bitmap = new SkBitmap;
-  if (!SkImageDecoder::DecodeMemory(bytes, size, bitmap)) {
-    ALOGE("SkImageDecoder::DecodeMemory() failed.");
-    return NULL;
-  }
-
-  return GraphicsJNI::createBitmap(env, bitmap,
-      GraphicsJNI::kBitmapCreateFlag_Premultiplied, NULL);
+  return decodeBitmap(env, (void*)bytes, size);
 }
 
 static void android_emoji_EmojiFactory_destructor(
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 4c08b4b..a2c1609 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -86,20 +86,26 @@
     return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
 }
 
-static void restore(JNIEnv* env, jobject, jlong canvasHandle) {
+static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
     Canvas* canvas = get_canvas(canvasHandle);
     if (canvas->getSaveCount() <= 1) {  // cannot restore anymore
-        doThrowISE(env, "Underflow in restore - more restores than saves");
-        return;
+        if (throwOnUnderflow) {
+            doThrowISE(env, "Underflow in restore - more restores than saves");
+        }
+        return; // compat behavior - return without throwing
     }
     canvas->restore();
 }
 
-static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount) {
+static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
+        jboolean throwOnUnderflow) {
     Canvas* canvas = get_canvas(canvasHandle);
     if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
-        doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
-        return;
+        if (throwOnUnderflow) {
+            doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
+            return;
+        }
+        restoreCount = 1; // compat behavior - restore as far as possible
     }
     canvas->restoreToCount(restoreCount);
 }
@@ -661,8 +667,8 @@
     {"native_saveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
     {"native_saveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
     {"native_getSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
-    {"native_restore","(J)V", (void*) CanvasJNI::restore},
-    {"native_restoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
+    {"native_restore","(JZ)V", (void*) CanvasJNI::restore},
+    {"native_restoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount},
     {"native_getCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
     {"native_setMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
     {"native_concat","(JJ)V", (void*) CanvasJNI::concat},
diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h
index 807dd32..32b5b02 100644
--- a/core/jni/android_media_AudioFormat.h
+++ b/core/jni/android_media_AudioFormat.h
@@ -25,6 +25,8 @@
 #define ENCODING_PCM_FLOAT  4
 #define ENCODING_AC3        5
 #define ENCODING_E_AC3      6
+#define ENCODING_DTS        7
+#define ENCODING_DTS_HD     8
 #define ENCODING_INVALID    0
 #define ENCODING_DEFAULT    1
 
@@ -46,6 +48,10 @@
         return AUDIO_FORMAT_AC3;
     case ENCODING_E_AC3:
         return AUDIO_FORMAT_E_AC3;
+    case ENCODING_DTS:
+        return AUDIO_FORMAT_DTS;
+    case ENCODING_DTS_HD:
+        return AUDIO_FORMAT_DTS_HD;
     case ENCODING_DEFAULT:
         return AUDIO_FORMAT_DEFAULT;
     default:
@@ -66,6 +72,10 @@
         return ENCODING_AC3;
     case AUDIO_FORMAT_E_AC3:
         return ENCODING_E_AC3;
+    case AUDIO_FORMAT_DTS:
+        return ENCODING_DTS;
+    case AUDIO_FORMAT_DTS_HD:
+        return ENCODING_DTS_HD;
     case AUDIO_FORMAT_DEFAULT:
         return ENCODING_DEFAULT;
     default:
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 4a98f27..fc05a6d 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -142,7 +142,14 @@
 
 static const char* const kEventHandlerClassPathName =
         "android/media/AudioPortEventHandler";
-static jmethodID gPostEventFromNative;
+static struct {
+    jfieldID    mJniCallback;
+} gEventHandlerFields;
+static struct {
+    jmethodID    postEventFromNative;
+} gAudioPortEventHandlerMethods;
+
+static Mutex gLock;
 
 enum AudioError {
     kAudioStatusOk = 0,
@@ -173,14 +180,14 @@
 private:
     void sendEvent(int event);
 
-    jclass      mClass;     // Reference to AudioPortEventHandlerDelegate class
-    jobject     mObject;    // Weak ref to AudioPortEventHandlerDelegate Java object to call on
+    jclass      mClass;     // Reference to AudioPortEventHandler class
+    jobject     mObject;    // Weak ref to AudioPortEventHandler Java object to call on
 };
 
 JNIAudioPortCallback::JNIAudioPortCallback(JNIEnv* env, jobject thiz, jobject weak_thiz)
 {
 
-    // Hold onto the SoundTriggerModule class for use in calling the static method
+    // Hold onto the AudioPortEventHandler class for use in calling the static method
     // that posts events to the application thread.
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
@@ -189,7 +196,7 @@
     }
     mClass = (jclass)env->NewGlobalRef(clazz);
 
-    // We use a weak reference so the SoundTriggerModule object can be garbage collected.
+    // We use a weak reference so the AudioPortEventHandler object can be garbage collected.
     // The reference is only used as a proxy for callbacks.
     mObject  = env->NewGlobalRef(weak_thiz);
 }
@@ -211,7 +218,7 @@
     if (env == NULL) {
         return;
     }
-    env->CallStaticVoidMethod(mClass, gPostEventFromNative, mObject,
+    env->CallStaticVoidMethod(mClass, gAudioPortEventHandlerMethods.postEventFromNative, mObject,
                               event, 0, 0, NULL);
     if (env->ExceptionCheck()) {
         ALOGW("An exception occurred while notifying an event.");
@@ -234,6 +241,23 @@
     sendEvent(AUDIOPORT_EVENT_SERVICE_DIED);
 }
 
+static sp<JNIAudioPortCallback> setJniCallback(JNIEnv* env,
+                                       jobject thiz,
+                                       const sp<JNIAudioPortCallback>& callback)
+{
+    Mutex::Autolock l(gLock);
+    sp<JNIAudioPortCallback> old =
+            (JNIAudioPortCallback*)env->GetLongField(thiz, gEventHandlerFields.mJniCallback);
+    if (callback.get()) {
+        callback->incStrong((void*)setJniCallback);
+    }
+    if (old != 0) {
+        old->decStrong((void*)setJniCallback);
+    }
+    env->SetLongField(thiz, gEventHandlerFields.mJniCallback, (jlong)callback.get());
+    return old;
+}
+
 static int check_AudioSystem_Command(status_t status)
 {
     switch (status) {
@@ -1355,7 +1379,9 @@
 
     sp<JNIAudioPortCallback> callback = new JNIAudioPortCallback(env, thiz, weak_this);
 
-    AudioSystem::setAudioPortCallback(callback);
+    if (AudioSystem::addAudioPortCallback(callback) == NO_ERROR) {
+        setJniCallback(env, thiz, callback);
+    }
 }
 
 static void
@@ -1363,9 +1389,11 @@
 {
     ALOGV("eventHandlerFinalize");
 
-    sp<JNIAudioPortCallback> callback;
+    sp<JNIAudioPortCallback> callback = setJniCallback(env, thiz, 0);
 
-    AudioSystem::setAudioPortCallback(callback);
+    if (callback != 0) {
+        AudioSystem::removeAudioPortCallback(callback);
+    }
 }
 
 static jint
@@ -1636,9 +1664,11 @@
                                                 "Landroid/media/AudioHandle;");
 
     jclass eventHandlerClass = FindClassOrDie(env, kEventHandlerClassPathName);
-    gPostEventFromNative = GetStaticMethodIDOrDie(env, eventHandlerClass, "postEventFromNative",
-                                                  "(Ljava/lang/Object;IIILjava/lang/Object;)V");
-
+    gAudioPortEventHandlerMethods.postEventFromNative = GetStaticMethodIDOrDie(
+                                                    env, eventHandlerClass, "postEventFromNative",
+                                                    "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    gEventHandlerFields.mJniCallback = GetFieldIDOrDie(env,
+                                                    eventHandlerClass, "mJniCallback", "J");
 
     jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
     gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index a7a925f..5552245 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -17,6 +17,8 @@
 
 #define LOG_TAG "AudioTrack-JNI"
 
+#include "android_media_AudioTrack.h"
+
 #include <JNIHelp.h>
 #include <JniConstants.h>
 #include "core_jni_helpers.h"
@@ -181,6 +183,12 @@
     env->SetLongField(thiz, javaAudioTrackFields.nativeTrackInJavaObj, (jlong)at.get());
     return old;
 }
+
+// ----------------------------------------------------------------------------
+sp<AudioTrack> android_media_AudioTrack_getAudioTrack(JNIEnv* env, jobject audioTrackObj) {
+    return getAudioTrack(env, audioTrackObj);
+}
+
 // ----------------------------------------------------------------------------
 static jint
 android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
diff --git a/core/jni/android_media_AudioTrack.h b/core/jni/android_media_AudioTrack.h
new file mode 100644
index 0000000..ef2aa66
--- /dev/null
+++ b/core/jni/android_media_AudioTrack.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_AUDIOTRACK_H
+#define ANDROID_MEDIA_AUDIOTRACK_H
+
+#include "jni.h"
+
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class AudioTrack;
+
+}; // namespace android
+
+/* Gets the underlying AudioTrack from an AudioTrack Java object. */
+extern android::sp<android::AudioTrack> android_media_AudioTrack_getAudioTrack(
+        JNIEnv* env, jobject audioTrackObj);
+
+#endif // ANDROID_MEDIA_AUDIOTRACK_H
diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp
index fb91c8f..9cf6a9d 100644
--- a/core/jni/android_view_InputDevice.cpp
+++ b/core/jni/android_view_InputDevice.cpp
@@ -48,11 +48,6 @@
         return NULL;
     }
 
-    ScopedLocalRef<jstring> uniqueIdObj(env, env->NewStringUTF(deviceInfo.getIdentifier().uniqueId));
-    if (!uniqueIdObj.get()) {
-        return NULL;
-    }
-
     ScopedLocalRef<jobject> kcmObj(env,
             android_view_KeyCharacterMap_create(env, deviceInfo.getId(),
             deviceInfo.getKeyCharacterMap()));
@@ -62,13 +57,16 @@
 
     const InputDeviceIdentifier& ident = deviceInfo.getIdentifier();
 
+    // Not sure why, but JNI is complaining when I pass this through directly.
+    jboolean hasMic = deviceInfo.hasMic() ? JNI_TRUE : JNI_FALSE;
+
     ScopedLocalRef<jobject> inputDeviceObj(env, env->NewObject(gInputDeviceClassInfo.clazz,
                 gInputDeviceClassInfo.ctor, deviceInfo.getId(), deviceInfo.getGeneration(),
                 deviceInfo.getControllerNumber(), nameObj.get(),
                 static_cast<int32_t>(ident.vendor), static_cast<int32_t>(ident.product),
-                uniqueIdObj.get(), descriptorObj.get(), deviceInfo.isExternal(),
-                deviceInfo.getSources(), deviceInfo.getKeyboardType(), kcmObj.get(),
-                deviceInfo.hasVibrator(), deviceInfo.hasButtonUnderPad()));
+                descriptorObj.get(), deviceInfo.isExternal(), deviceInfo.getSources(),
+                deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(),
+                hasMic, deviceInfo.hasButtonUnderPad()));
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     for (size_t i = 0; i < ranges.size(); i++) {
@@ -90,7 +88,7 @@
     gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz);
 
     gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>",
-            "(IIILjava/lang/String;IILjava/lang/String;Ljava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZ)V");
+            "(IIILjava/lang/String;IILjava/lang/String;ZIILandroid/view/KeyCharacterMap;ZZZ)V");
 
     gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz,
             "addMotionRange", "(IIFFFFF)V");
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 3796c9c..7c5d194 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -56,6 +56,8 @@
     <protected-broadcast android:name="android.intent.action.ACTION_POWER_CONNECTED" />
     <protected-broadcast android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
     <protected-broadcast android:name="android.intent.action.ACTION_SHUTDOWN" />
+    <protected-broadcast android:name="android.intent.action.CHARGING" />
+    <protected-broadcast android:name="android.intent.action.DISCHARGING" />
     <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_LOW" />
     <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" />
     <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_FULL" />
@@ -306,82 +308,133 @@
     <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" />
 
     <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
+    <protected-broadcast android:name="android.service.persistentdata.action.WIPE_IF_ALLOWED" />
 
-    <!-- ====================================== -->
-    <!-- Permissions for things that cost money -->
-    <!-- ====================================== -->
+    <!-- ====================================================================== -->
+    <!--                          RUNTIME PERMISSIONS                           -->
+    <!-- ====================================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that can be used to make the user spend money
-         without their direct involvement. -->
-    <permission-group android:name="android.permission-group.COST_MONEY"
-        android:label="@string/permgrouplab_costMoney"
-        android:description="@string/permgroupdesc_costMoney" />
-
-    <!-- ================================== -->
-    <!-- Permissions for accessing messages -->
-    <!-- ================================== -->
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing user's contacts including personal profile   -->
+    <!-- ====================================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that allow an application to send messages
-         on behalf of the user or intercept messages being received by the
-         user.  This is primarily intended for SMS/MMS messaging, such as
-         receiving or reading an MMS. -->
-    <permission-group android:name="android.permission-group.MESSAGES"
-        android:label="@string/permgrouplab_messages"
+    <!-- Used for runtime permissions related to user's contacts and profile. -->
+    <permission-group android:name="android.permission-group.CONTACTS"
+        android:icon="@drawable/perm_group_social_info"
+        android:label="@string/permgrouplab_contacts"
+        android:description="@string/permgroupdesc_contacts"
+        android:priority="100" />
+
+    <!-- Allows an application to read the user's contacts data. -->
+    <permission android:name="android.permission.READ_CONTACTS"
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:label="@string/permlab_readContacts"
+        android:description="@string/permdesc_readContacts"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to write the user's contacts data. -->
+    <permission android:name="android.permission.WRITE_CONTACTS"
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:label="@string/permlab_writeContacts"
+        android:description="@string/permdesc_writeContacts"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to read the user's personal profile data. -->
+    <permission android:name="android.permission.READ_PROFILE"
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:label="@string/permlab_readProfile"
+        android:description="@string/permdesc_readProfile"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to write the user's personal profile data. -->
+    <permission android:name="android.permission.WRITE_PROFILE"
+        android:permissionGroup="android.permission-group.CONTACTS"
+        android:label="@string/permlab_writeProfile"
+        android:description="@string/permdesc_writeProfile"
+        android:protectionLevel="dangerous" />
+
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing user's calendar                              -->
+    <!-- ====================================================================== -->
+    <eat-comment />
+
+    <!-- Used for runtime permissions related to user's calendar. -->
+    <permission-group android:name="android.permission-group.CALENDAR"
+        android:icon="@drawable/perm_group_calendar"
+        android:label="@string/permgrouplab_calendar"
+        android:description="@string/permgroupdesc_calendar"
+        android:priority="200" />
+
+    <!-- Allows an application to read the user's calendar data. -->
+    <permission android:name="android.permission.READ_CALENDAR"
+        android:permissionGroup="android.permission-group.CALENDAR"
+        android:label="@string/permlab_readCalendar"
+        android:description="@string/permdesc_readCalendar"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to write the user's calendar data. -->
+    <permission android:name="android.permission.WRITE_CALENDAR"
+        android:permissionGroup="android.permission-group.CALENDAR"
+        android:label="@string/permlab_writeCalendar"
+        android:description="@string/permdesc_writeCalendar"
+        android:protectionLevel="dangerous" />
+
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing and modifying user's SMS messages            -->
+    <!-- ====================================================================== -->
+    <eat-comment />
+
+    <!-- Used for runtime permissions related to user's SMS messages. -->
+    <permission-group android:name="android.permission-group.SMS"
         android:icon="@drawable/perm_group_messages"
-        android:description="@string/permgroupdesc_messages"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="360"/>
+        android:label="@string/permgrouplab_sms"
+        android:description="@string/permgroupdesc_sms"
+        android:priority="300" />
 
     <!-- Allows an application to send SMS messages. -->
     <permission android:name="android.permission.SEND_SMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
-        android:permissionFlags="costsMoney"
+        android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_sendSms"
-        android:description="@string/permdesc_sendSms" />
+        android:description="@string/permdesc_sendSms"
+        android:permissionFlags="costsMoney"
+        android:protectionLevel="dangerous" />
 
-    <!-- @SystemApi Allows an application (Phone) to send a request to other applications
-         to handle the respond-via-message action during incoming calls.
-         <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_sendRespondViaMessageRequest"
-        android:description="@string/permdesc_sendRespondViaMessageRequest" />
-
-    <!-- Allows an application to monitor incoming SMS messages, to record
-         or perform processing on them. -->
+    <!-- Allows an application to receive SMS messages. -->
     <permission android:name="android.permission.RECEIVE_SMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
+        android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_receiveSms"
-        android:description="@string/permdesc_receiveSms" />
+        android:description="@string/permdesc_receiveSms"
+        android:protectionLevel="dangerous"/>
 
-    <!-- Allows an application to monitor incoming MMS messages, to record
-         or perform processing on them. -->
+    <!-- Allows an application to read SMS messages. -->
+    <permission android:name="android.permission.READ_SMS"
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_readSms"
+        android:description="@string/permdesc_readSms"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to write SMS messages. -->
+    <permission android:name="android.permission.WRITE_SMS"
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_writeSms"
+        android:description="@string/permdesc_writeSms"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to receive WAP push messages. -->
+    <permission android:name="android.permission.RECEIVE_WAP_PUSH"
+        android:permissionGroup="android.permission-group.SMS"
+        android:label="@string/permlab_receiveWapPush"
+        android:description="@string/permdesc_receiveWapPush"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to monitor incoming MMS messages. -->
     <permission android:name="android.permission.RECEIVE_MMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
+        android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_receiveMms"
-        android:description="@string/permdesc_receiveMms" />
-
-    <!-- Allows an application to filter carrier specific sms.
-         @hide -->
-    <permission android:name="android.permission.CARRIER_FILTER_SMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="signature|system" />
-
-    <!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
-         to record or display them to the user.
-         <p>Not for use by third-party applications.
-         @hide Pending API council approval -->
-    <permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_receiveEmergencyBroadcast"
-        android:description="@string/permdesc_receiveEmergencyBroadcast" />
+        android:description="@string/permdesc_receiveMms"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to read previously received cell broadcast
          messages and to register a content observer to get notifications when
@@ -395,43 +448,13 @@
          to the user until after the initial alert dialog is dismissed.
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_CELL_BROADCASTS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
+        android:permissionGroup="android.permission-group.SMS"
         android:label="@string/permlab_readCellBroadcasts"
-        android:description="@string/permdesc_readCellBroadcasts" />
-
-    <!-- Allows an application to read SMS messages. -->
-    <permission android:name="android.permission.READ_SMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readSms"
-        android:description="@string/permdesc_readSms" />
-
-    <!-- Allows an application to write SMS messages. -->
-    <permission android:name="android.permission.WRITE_SMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_writeSms"
-        android:description="@string/permdesc_writeSms" />
-
-    <!-- Allows an application to monitor incoming WAP push messages. -->
-    <permission android:name="android.permission.RECEIVE_WAP_PUSH"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_receiveWapPush"
-        android:description="@string/permdesc_receiveWapPush" />
-
-    <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
-         or perform processing on them. -->
-    <!-- @hide -->
-    <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_receiveBluetoothMap"
-        android:description="@string/permdesc_receiveBluetoothMap" />
+        android:description="@string/permdesc_readCellBroadcasts"
+        android:protectionLevel="dangerous" />
 
     <!-- =============================================================== -->
-    <!-- Permissions for accessing social info (contacts and social) -->
+    <!-- Permissions for accessing social info                           -->
     <!-- =============================================================== -->
     <eat-comment />
 
@@ -445,66 +468,11 @@
         android:icon="@drawable/perm_group_social_info"
         android:description="@string/permgroupdesc_socialInfo"
         android:permissionGroupFlags="personalInfo"
-        android:priority="320" />
+        android:priority="1200" />
 
-    <!-- Allows an application to read the user's contacts data. -->
-    <permission android:name="android.permission.READ_CONTACTS"
-        android:permissionGroup="android.permission-group.SOCIAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readContacts"
-        android:description="@string/permdesc_readContacts" />
-
-    <!-- Allows an application to write (but not read) the user's
-         contacts data. -->
-    <permission android:name="android.permission.WRITE_CONTACTS"
-        android:permissionGroup="android.permission-group.SOCIAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_writeContacts"
-        android:description="@string/permdesc_writeContacts" />
-
-    <!-- @SystemApi @hide Allows an application to execute contacts directory search.
-         This should only be used by ContactsProvider.
-         <p>Not for use by third-party applications. -->
-    <permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="signature|system" />
-
-    <!-- Allows an application to read the user's call log.
-         <p class="note"><strong>Note:</strong> If your app uses the
-         {@link #READ_CONTACTS} permission and <em>both</em> your <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-         minSdkVersion}</a> and <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
-         grants your app this permission. If you don't need this permission, be sure your <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 16 or higher.</p> -->
-    <permission android:name="android.permission.READ_CALL_LOG"
-        android:permissionGroup="android.permission-group.SOCIAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readCallLog"
-        android:description="@string/permdesc_readCallLog" />
-
-    <!-- Allows an application to write (but not read) the user's
-         contacts data.
-         <p class="note"><strong>Note:</strong> If your app uses the
-         {@link #WRITE_CONTACTS} permission and <em>both</em> your <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-         minSdkVersion}</a> and <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
-         grants your app this permission. If you don't need this permission, be sure your <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 16 or higher.</p>  -->
-    <permission android:name="android.permission.WRITE_CALL_LOG"
-        android:permissionGroup="android.permission-group.SOCIAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_writeCallLog"
-        android:description="@string/permdesc_writeCallLog" />
-
-  <!-- Allows an application to read from the user's social stream.
-       @deprecated This functionality will be unsupported in the future; cursors returned
-       will be empty. Please do not use. -->
+    <!-- Allows an application to read from the user's social stream.
+         @deprecated This functionality will be unsupported in the future; cursors returned
+         will be empty. Please do not use. -->
     <permission android:name="android.permission.READ_SOCIAL_STREAM"
         android:permissionGroup="android.permission-group.SOCIAL_INFO"
         android:protectionLevel="dangerous"
@@ -521,78 +489,255 @@
         android:label="@string/permlab_writeSocialStream"
         android:description="@string/permdesc_writeSocialStream" />
 
-    <!-- =============================================================== -->
-    <!-- Permissions for accessing information about the device owner    -->
-    <!-- =============================================================== -->
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing the device location                          -->
+    <!-- ====================================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to information about the device
-         user such as profile information.  This includes both reading and
-         writing of this data (which should generally be expressed as two
-         distinct permissions). -->
-    <permission-group android:name="android.permission-group.PERSONAL_INFO"
-        android:label="@string/permgrouplab_personalInfo"
-        android:icon="@drawable/perm_group_personal_info"
-        android:description="@string/permgroupdesc_personalInfo"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="310" />
+    <!-- Used for permissions that allow accessing the device location. -->
+    <permission-group android:name="android.permission-group.LOCATION"
+        android:icon="@drawable/perm_group_location"
+        android:label="@string/permgrouplab_location"
+        android:description="@string/permgroupdesc_location"
+        android:priority="400" />
 
-    <!-- Allows an application to read the user's personal profile data. -->
-    <permission android:name="android.permission.READ_PROFILE"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readProfile"
-        android:description="@string/permdesc_readProfile" />
+    <!-- Allows an app to access precise location. -->
+    <permission android:name="android.permission.ACCESS_FINE_LOCATION"
+        android:permissionGroup="android.permission-group.LOCATION"
+        android:label="@string/permlab_accessFineLocation"
+        android:description="@string/permdesc_accessFineLocation"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an app to access approximate location. -->
+    <permission android:name="android.permission.ACCESS_COARSE_LOCATION"
+        android:permissionGroup="android.permission-group.LOCATION"
+        android:label="@string/permlab_accessCoarseLocation"
+        android:description="@string/permdesc_accessCoarseLocation"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to create mock location providers for testing. -->
+    <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
+        android:permissionGroup="android.permission-group.LOCATION"
+        android:label="@string/permlab_accessMockLocation"
+        android:description="@string/permdesc_accessMockLocation"
+        android:protectionLevel="dangerous" />
+
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing the device telephony                         -->
+    <!-- ====================================================================== -->
+    <eat-comment />
+
+    <!-- Used for permissions that are associated telephony features. -->
+    <permission-group android:name="android.permission-group.PHONE"
+        android:icon="@drawable/perm_group_phone_calls"
+        android:label="@string/permgrouplab_phone"
+        android:description="@string/permgroupdesc_phone"
+        android:priority="500" />
+
+    <!-- Allows read only access to phone state.
+         <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+         minSdkVersion}</a> and <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+         targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+         grants your app this permission. If you don't need this permission, be sure your <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+         targetSdkVersion}</a> is 4 or higher. -->
+    <permission android:name="android.permission.READ_PHONE_STATE"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_readPhoneState"
+        android:description="@string/permdesc_readPhoneState"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to initiate a phone call without going through
+        the Dialer user interface for the user to confirm the call. -->
+    <permission android:name="android.permission.CALL_PHONE"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:permissionFlags="costsMoney"
+        android:label="@string/permlab_callPhone"
+        android:description="@string/permdesc_callPhone"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to read the user's call log.
+         <p class="note"><strong>Note:</strong> If your app uses the
+         {@link #READ_CONTACTS} permission and <em>both</em> your <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+         minSdkVersion}</a> and <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+         targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
+         grants your app this permission. If you don't need this permission, be sure your <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+         targetSdkVersion}</a> is 16 or higher.</p> -->
+    <permission android:name="android.permission.READ_CALL_LOG"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_readCallLog"
+        android:description="@string/permdesc_readCallLog"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write (but not read) the user's
-         personal profile data. -->
-    <permission android:name="android.permission.WRITE_PROFILE"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_writeProfile"
-        android:description="@string/permdesc_writeProfile" />
+         contacts data.
+         <p class="note"><strong>Note:</strong> If your app uses the
+         {@link #WRITE_CONTACTS} permission and <em>both</em> your <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+         minSdkVersion}</a> and <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+         targetSdkVersion}</a> values are set to 15 or lower, the system implicitly
+         grants your app this permission. If you don't need this permission, be sure your <a
+         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+         targetSdkVersion}</a> is 16 or higher.</p>  -->
+    <permission android:name="android.permission.WRITE_CALL_LOG"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_writeCallLog"
+        android:description="@string/permdesc_writeCallLog"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to add voicemails into the system. -->
+    <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_addVoicemail"
+        android:description="@string/permdesc_addVoicemail"
+        android:protectionLevel="dangerous" />
+
+    <!-- Allows an application to use SIP service. -->
+    <permission android:name="android.permission.USE_SIP"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:description="@string/permdesc_use_sip"
+        android:label="@string/permlab_use_sip"
+        android:protectionLevel="dangerous"/>
+
+    <!-- Allows an application to see the number being dialed during an outgoing
+         call with the option to redirect the call to a different number or
+         abort the call altogether. -->
+    <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
+        android:permissionGroup="android.permission-group.PHONE"
+        android:label="@string/permlab_processOutgoingCalls"
+        android:description="@string/permdesc_processOutgoingCalls"
+        android:protectionLevel="dangerous" />
+
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing the device microphone                        -->
+    <!-- ====================================================================== -->
+    <eat-comment />
+
+    <!-- Used for permissions that are associated with accessing
+         microphone audio from the device. Note that phone calls also capture audio
+         but are in a separate (more visible) permission group. -->
+    <permission-group android:name="android.permission-group.MICROPHONE"
+        android:icon="@drawable/perm_group_microphone"
+        android:label="@string/permgrouplab_microphone"
+        android:description="@string/permgroupdesc_microphone"
+        android:priority="600" />
+
+    <!-- Allows an application to record audio. -->
+    <permission android:name="android.permission.RECORD_AUDIO"
+        android:permissionGroup="android.permission-group.MICROPHONE"
+        android:label="@string/permlab_recordAudio"
+        android:description="@string/permdesc_recordAudio"
+        android:protectionLevel="dangerous"/>
+
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing the device camera                            -->
+    <!-- ====================================================================== -->
+    <eat-comment />
+
+    <!-- Used for permissions that are associated with accessing
+     camera or capturing images/video from the device. -->
+    <permission-group android:name="android.permission-group.CAMERA"
+        android:icon="@drawable/perm_group_camera"
+        android:label="@string/permgrouplab_camera"
+        android:description="@string/permgroupdesc_camera"
+        android:priority="700" />
+
+    <!-- Required to be able to access the camera device.
+         <p>This will automatically enforce the <a
+         href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code
+         &lt;uses-feature&gt;}</a> manifest element for <em>all</em> camera features.
+         If you do not require all camera features or can properly operate if a camera
+         is not available, then you must modify your manifest as appropriate in order to
+         install on devices that don't support all camera features.</p> -->
+    <permission android:name="android.permission.CAMERA"
+        android:permissionGroup="android.permission-group.CAMERA"
+        android:label="@string/permlab_camera"
+        android:description="@string/permdesc_camera"
+        android:protectionLevel="dangerous" />
+
+
+    <!-- ====================================================================== -->
+    <!-- Permissions for accessing the device sensors                           -->
+    <!-- ====================================================================== -->
+    <eat-comment />
+
+    <!-- Used for permissions that are associated with accessing
+         camera or capturing images/video from the device. -->
+    <permission-group android:name="android.permission-group.SENSORS"
+        android:label="@string/permgrouplab_sensors"
+        android:description="@string/permgroupdesc_sensors"
+        android:priority="800" />
 
     <!-- Allows an application to access data from sensors that the user uses to
          measure what is happening inside his/her body, such as heart rate. -->
     <permission android:name="android.permission.BODY_SENSORS"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
+        android:permissionGroup="android.permission-group.SENSORS"
         android:label="@string/permlab_bodySensors"
-        android:description="@string/permdesc_bodySensors" />
+        android:description="@string/permdesc_bodySensors"
+        android:protectionLevel="dangerous" />
 
-    <!-- =============================================================== -->
-    <!-- Permissions for accessing the device calendar                   -->
-    <!-- =============================================================== -->
+    <!-- Allows an app to use fingerprint hardware. -->
+    <permission android:name="android.permission.USE_FINGERPRINT"
+        android:label="@string/permlab_useFingerprint"
+        android:description="@string/permdesc_useFingerprint"
+        android:protectionLevel="dangerous" />
+
+    <!-- ====================================================================== -->
+    <!-- INSTALLTIME PERMISSIONS                                                -->
+    <!-- ====================================================================== -->
+
+    <!-- ================================== -->
+    <!-- Permissions for accessing messages -->
+    <!-- ================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to the device
-         calendar to create / view events.-->
-    <permission-group android:name="android.permission-group.CALENDAR"
-        android:label="@string/permgrouplab_calendar"
-        android:icon="@drawable/perm_group_calendar"
-        android:description="@string/permgroupdesc_calendar"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="290" />
+    <!-- @SystemApi Allows an application (Phone) to send a request to other applications
+         to handle the respond-via-message action during incoming calls.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE"
+        android:protectionLevel="signature|system" />
 
-    <!-- Allows an application to read the user's calendar data. -->
-    <permission android:name="android.permission.READ_CALENDAR"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readCalendar"
-        android:description="@string/permdesc_readCalendar" />
+    <!-- Allows an application to filter carrier specific sms.
+         @hide -->
+    <permission android:name="android.permission.CARRIER_FILTER_SMS"
+        android:protectionLevel="signature|system" />
 
-    <!-- Allows an application to write (but not read) the user's
-         calendar data. -->
-    <permission android:name="android.permission.WRITE_CALENDAR"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_writeCalendar"
-        android:description="@string/permdesc_writeCalendar" />
+    <!-- @SystemApi Allows an application to receive emergency cell broadcast messages,
+         to record or display them to the user.
+         <p>Not for use by third-party applications.
+         @hide Pending API council approval -->
+    <permission android:name="android.permission.RECEIVE_EMERGENCY_BROADCAST"
+        android:protectionLevel="signature|system" />
+
+    <!-- Allows an application to monitor incoming Bluetooth MAP messages, to record
+         or perform processing on them. -->
+    <!-- @hide -->
+    <permission android:name="android.permission.RECEIVE_BLUETOOTH_MAP"
+        android:protectionLevel="signature|system" />
+
+    <!-- @SystemApi @hide Allows an application to execute contacts directory search.
+         This should only be used by ContactsProvider.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.BIND_DIRECTORY_SEARCH"
+        android:protectionLevel="signature|system" />
 
     <!-- =============================================================== -->
     <!-- Permissions for accessing the user dictionary-->
     <!-- =============================================================== -->
     <eat-comment />
 
+
+    <!-- =============================================================== -->
+    <!-- Permissions for accessing the user dictionary                   -->
+    <!-- =============================================================== -->
+    <eat-comment />
+
     <!-- Used for permissions that provide access to the user
          calendar to create / view events.-->
     <permission-group android:name="android.permission-group.USER_DICTIONARY"
@@ -600,31 +745,23 @@
         android:icon="@drawable/perm_group_user_dictionary"
         android:description="@string/permgroupdesc_dictionary"
         android:permissionGroupFlags="personalInfo"
-        android:priority="170" />
+        android:priority="1100" />
 
     <!-- Allows an application to read the user dictionary. This should
          really only be required by an IME, or a dictionary editor like
          the Settings app. -->
     <permission android:name="android.permission.READ_USER_DICTIONARY"
         android:permissionGroup="android.permission-group.USER_DICTIONARY"
-        android:protectionLevel="dangerous"
         android:label="@string/permlab_readDictionary"
-        android:description="@string/permdesc_readDictionary" />
-
-    <!-- Used for permissions that provide access to the user
-         calendar to create / view events.-->
-    <permission-group android:name="android.permission-group.WRITE_USER_DICTIONARY"
-        android:label="@string/permgrouplab_writeDictionary"
-        android:icon="@drawable/perm_group_user_dictionary_write"
-        android:description="@string/permgroupdesc_writeDictionary"
-        android:priority="160" />
+        android:description="@string/permdesc_readDictionary"
+        android:protectionLevel="dangerous"/>
 
     <!-- Allows an application to write to the user dictionary. -->
     <permission android:name="android.permission.WRITE_USER_DICTIONARY"
-        android:permissionGroup="android.permission-group.WRITE_USER_DICTIONARY"
-        android:protectionLevel="normal"
+        android:permissionGroup="android.permission-group.USER_DICTIONARY"
         android:label="@string/permlab_writeDictionary"
-        android:description="@string/permdesc_writeDictionary" />
+        android:description="@string/permdesc_writeDictionary"
+        android:protectionLevel="normal"/>
 
     <!-- =============================================================== -->
     <!-- Permissions for accessing the user bookmarks                    -->
@@ -638,7 +775,7 @@
         android:icon="@drawable/perm_group_bookmarks"
         android:description="@string/permgroupdesc_bookmarks"
         android:permissionGroupFlags="personalInfo"
-        android:priority="300" />
+        android:priority="1200" />
 
     <!-- Allows an application to read (but not write) the user's
         browsing history and bookmarks. -->
@@ -661,18 +798,8 @@
     <!-- =============================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to device alarms. -->
-    <permission-group android:name="android.permission-group.DEVICE_ALARMS"
-        android:label="@string/permgrouplab_deviceAlarms"
-        android:icon="@drawable/perm_group_device_alarms"
-        android:description="@string/permgroupdesc_deviceAlarms"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="210" />
-
-    <!-- Allows an application to broadcast an Intent to set an alarm for the
-         user. -->
+    <!-- Allows an application to broadcast an Intent to set an alarm for the user. -->
     <permission android:name="com.android.alarm.permission.SET_ALARM"
-        android:permissionGroup="android.permission-group.DEVICE_ALARMS"
         android:label="@string/permlab_setAlarm"
         android:description="@string/permdesc_setAlarm"
         android:protectionLevel="normal" />
@@ -682,97 +809,29 @@
     <!-- =============================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to the user voicemail box. -->
-    <permission-group android:name="android.permission-group.VOICEMAIL"
-        android:label="@string/permgrouplab_voicemail"
-        android:icon="@drawable/perm_group_voicemail"
-        android:description="@string/permgroupdesc_voicemail"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="280" />
-
-    <!-- Allows an application to add voicemails into the system. -->
-    <permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL"
-        android:permissionGroup="android.permission-group.VOICEMAIL"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_addVoicemail"
-        android:description="@string/permdesc_addVoicemail" />
-
     <!-- Allows an application to modify and remove existing voicemails in the system -->
     <permission android:name="com.android.voicemail.permission.WRITE_VOICEMAIL"
-        android:permissionGroup="android.permission-group.VOICEMAIL"
-        android:protectionLevel="system|signature"
-        android:label="@string/permlab_writeVoicemail"
-        android:description="@string/permdesc_writeVoicemail" />
+        android:protectionLevel="system|signature" />
 
     <!-- Allows an application to read voicemails in the system. -->
     <permission android:name="com.android.voicemail.permission.READ_VOICEMAIL"
-        android:permissionGroup="android.permission-group.VOICEMAIL"
-        android:protectionLevel="system|signature"
-        android:label="@string/permlab_readVoicemail"
-        android:description="@string/permdesc_readVoicemail" />
-
-    <!-- =============================================== -->
-    <!-- Permissions for enabling accessibility features -->
-    <!-- =============================================== -->
-    <eat-comment />
-
-    <!-- Used for permissions that allow requesting certain accessibility features. -->
-    <permission-group android:name="android.permission-group.ACCESSIBILITY_FEATURES"
-        android:label="@string/permgrouplab_accessibilityFeatures"
-        android:icon="@drawable/perm_group_accessibility_features"
-        android:description="@string/permgroupdesc_accessibilityFeatures"
-        android:priority="380" />
+        android:protectionLevel="system|signature" />
 
     <!-- ======================================= -->
     <!-- Permissions for accessing location info -->
     <!-- ======================================= -->
     <eat-comment />
 
-    <!-- Used for permissions that allow access to the user's current
-         location. -->
-    <permission-group android:name="android.permission-group.LOCATION"
-        android:label="@string/permgrouplab_location"
-        android:icon="@drawable/perm_group_location"
-        android:description="@string/permgroupdesc_location"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="330" />
-
-    <!-- Allows an app to access precise location from location sources such
-         as GPS, cell towers, and Wi-Fi. -->
-    <permission android:name="android.permission.ACCESS_FINE_LOCATION"
-        android:permissionGroup="android.permission-group.LOCATION"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_accessFineLocation"
-        android:description="@string/permdesc_accessFineLocation" />
-
-    <!-- Allows an app to access approximate location derived from network location
-         sources such as cell towers and Wi-Fi. -->
-    <permission android:name="android.permission.ACCESS_COARSE_LOCATION"
-        android:permissionGroup="android.permission-group.LOCATION"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_accessCoarseLocation"
-        android:description="@string/permdesc_accessCoarseLocation" />
-
-    <!-- Allows an application to create mock location providers for testing -->
-    <permission android:name="android.permission.ACCESS_MOCK_LOCATION"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_accessMockLocation"
-        android:description="@string/permdesc_accessMockLocation" />
-
     <!-- Allows an application to access extra location provider commands -->
     <permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="normal"
         android:label="@string/permlab_accessLocationExtraCommands"
-        android:description="@string/permdesc_accessLocationExtraCommands" />
+        android:description="@string/permdesc_accessLocationExtraCommands"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to install a location provider into the Location Manager.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INSTALL_LOCATION_PROVIDER"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_installLocationProvider"
-        android:description="@string/permdesc_installLocationProvider" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi @hide Allows HDMI-CEC service to access device and configuration files.
          This should only be used by HDMI-CEC service.
@@ -784,7 +843,6 @@
          such as the geofencing api.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.LOCATION_HARDWARE"
-        android:permissionGroup="android.permission-group.LOCATION"
         android:protectionLevel="signature|system" />
     <uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
 
@@ -793,169 +851,124 @@
     <!-- ======================================= -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to networking services.  The
-         main permission here is internet access, but this is also an
-         appropriate group for accessing or modifying any network configuration
-         or other related network operations. -->
-    <permission-group android:name="android.permission-group.NETWORK"
-        android:label="@string/permgrouplab_network"
-        android:icon="@drawable/perm_group_network"
-        android:description="@string/permgroupdesc_network"
-        android:priority="270" />
-
     <!-- Allows applications to open network sockets. -->
     <permission android:name="android.permission.INTERNET"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_createNetworkSockets"
-        android:label="@string/permlab_createNetworkSockets" />
+        android:label="@string/permlab_createNetworkSockets"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows applications to access information about networks -->
     <permission android:name="android.permission.ACCESS_NETWORK_STATE"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_accessNetworkState"
-        android:label="@string/permlab_accessNetworkState" />
+        android:label="@string/permlab_accessNetworkState"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to access information about Wi-Fi networks -->
     <permission android:name="android.permission.ACCESS_WIFI_STATE"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_accessWifiState"
-        android:label="@string/permlab_accessWifiState" />
+        android:label="@string/permlab_accessWifiState"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to change Wi-Fi connectivity state -->
     <permission android:name="android.permission.CHANGE_WIFI_STATE"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_changeWifiState"
-        android:label="@string/permlab_changeWifiState" />
+        android:label="@string/permlab_changeWifiState"
+        android:protectionLevel="dangerous" />
 
     <!-- @SystemApi @hide Allows applications to read Wi-Fi credential.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_WIFI_CREDENTIAL"
-        android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi @hide Allow system apps to receive broadcast
          when a wifi network credential is changed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE"
-        android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi @hide Allows an application to modify any wifi configuration, even if created
-	 by another application. Once reconfigured the original creator canot make any further
-	 modifications.
-	 <p>Not for use by third-party applications. -->
+     by another application. Once reconfigured the original creator cannot make any further
+     modifications.
+     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.OVERRIDE_WIFI_CONFIG"
-	android:permissionGroup="android.permission-group.NETWORK"
-	android:protectionLevel="signature|system" />
+        android:protectionLevel="signature|system" />
 
     <!-- @hide -->
     <permission android:name="android.permission.ACCESS_WIMAX_STATE"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_accessWimaxState"
-        android:label="@string/permlab_accessWimaxState" />
+        android:label="@string/permlab_accessWimaxState"
+        android:protectionLevel="normal" />
 
     <!-- @hide -->
     <permission android:name="android.permission.CHANGE_WIMAX_STATE"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_changeWimaxState"
-        android:label="@string/permlab_changeWimaxState" />
+        android:label="@string/permlab_changeWimaxState"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows applications to act as network scorers. @hide @SystemApi-->
-    <!-- TODO: Change protection level to normal when unhiding this API. -->
     <permission android:name="android.permission.SCORE_NETWORKS"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="signature|system"
-        android:description="@string/permdesc_scoreNetworks"
-        android:label="@string/permlab_scoreNetworks" />
+        android:protectionLevel="signature|system" />
 
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
     <eat-comment />
 
-    <!-- Used for permissions that provide access to other devices through Bluetooth.-->
-    <permission-group android:name="android.permission-group.BLUETOOTH_NETWORK"
-        android:label="@string/permgrouplab_bluetoothNetwork"
-        android:icon="@drawable/perm_group_bluetooth"
-        android:description="@string/permgroupdesc_bluetoothNetwork"
-        android:priority="260" />
-
     <!-- Allows applications to connect to paired bluetooth devices -->
     <permission android:name="android.permission.BLUETOOTH"
-        android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_bluetooth"
-        android:label="@string/permlab_bluetooth" />
+        android:label="@string/permlab_bluetooth"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows applications to discover and pair bluetooth devices -->
     <permission android:name="android.permission.BLUETOOTH_ADMIN"
-        android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_bluetoothAdmin"
-        android:label="@string/permlab_bluetoothAdmin" />
+        android:label="@string/permlab_bluetoothAdmin"
+        android:protectionLevel="dangerous" />
 
     <!-- @SystemApi Allows applications to pair bluetooth devices without user interaction, and to
          allow or disallow phonebook access or message access.
          This is not available to third party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
-        android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
-        android:protectionLevel="system|signature"
-        android:description="@string/permdesc_bluetoothPriv"
-        android:label="@string/permlab_bluetoothPriv" />
+        android:protectionLevel="system|signature" />
 
     <!-- Control access to email providers exclusively for Bluetooth
          @hide
     -->
     <permission android:name="android.permission.BLUETOOTH_MAP"
-        android:permissionGroup="android.permission-group.BLUETOOTH_NETWORK"
-        android:protectionLevel="signature"
-        android:description="@string/permdesc_bluetoothMap"
-        android:label="@string/permlab_bluetoothMap" />
+        android:protectionLevel="signature" />
 
     <!-- Allows bluetooth stack to access files
          @hide This should only be used by Bluetooth apk.
     -->
     <permission android:name="android.permission.BLUETOOTH_STACK"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />
 
     <!-- Allows applications to perform I/O operations over NFC -->
     <permission android:name="android.permission.NFC"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_nfc"
-        android:label="@string/permlab_nfc" />
+        android:label="@string/permlab_nfc"
+        android:protectionLevel="dangerous" />
 
     <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
          @hide -->
     <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
-        android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
-    <!-- @SystemApi @hide -->
+    <!-- @SystemApi
+         @hide -->
     <permission android:name="android.permission.RECEIVE_DATA_ACTIVITY_CHANGE"
-        android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows access to the loop radio (Android@Home mesh network) device.
          @hide -->
     <permission android:name="android.permission.LOOP_RADIO"
-        android:permissionGroup="android.permission-group.NETWORK"
         android:protectionLevel="signature|system" />
 
     <!-- Allows sending and receiving handover transfer status from Wifi and Bluetooth
-         @hide
-    -->
+         @hide -->
     <permission android:name="android.permission.NFC_HANDOVER_STATUS"
-                android:label="@string/permlab_handoverStatus"
-                android:description="@string/permdesc_handoverStatus"
-                android:protectionLevel="signature|system" />
+        android:protectionLevel="signature|system" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
@@ -969,7 +982,7 @@
         android:icon="@drawable/perm_group_accounts"
         android:description="@string/permgroupdesc_accounts"
         android:permissionGroupFlags="personalInfo"
-        android:priority="200" />
+        android:priority="1000" />
 
     <!-- Allows access to the list of accounts in the Accounts Service -->
     <permission android:name="android.permission.GET_ACCOUNTS"
@@ -1004,135 +1017,88 @@
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCOUNT_MANAGER"
         android:permissionGroup="android.permission-group.ACCOUNTS"
-        android:protectionLevel="signature"
-        android:description="@string/permdesc_accountManagerService"
-        android:label="@string/permlab_accountManagerService" />
+        android:protectionLevel="signature" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing hardware that may effect battery life-->
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide direct access to the hardware on
-         the device that has an effect on battery life.  This includes vibrator,
-         flashlight,  etc. -->
-
-    <permission-group android:name="android.permission-group.AFFECTS_BATTERY"
-        android:label="@string/permgrouplab_affectsBattery"
-        android:icon="@drawable/perm_group_affects_battery"
-        android:description="@string/permgroupdesc_affectsBattery"
-        android:priority="180" />
-
     <!-- Allows applications to enter Wi-Fi Multicast mode -->
     <permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
-        android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_changeWifiMulticastState"
-        android:label="@string/permlab_changeWifiMulticastState" />
+        android:label="@string/permlab_changeWifiMulticastState"
+        android:protectionLevel="dangerous" />
 
     <!-- Allows access to the vibrator -->
     <permission android:name="android.permission.VIBRATE"
-        android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
-        android:protectionLevel="normal"
         android:label="@string/permlab_vibrate"
-        android:description="@string/permdesc_vibrate" />
+        android:description="@string/permdesc_vibrate"
+        android:protectionLevel="normal" />
 
     <!-- Allows access to the flashlight -->
     <permission android:name="android.permission.FLASHLIGHT"
-        android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
-        android:protectionLevel="normal"
         android:label="@string/permlab_flashlight"
-        android:description="@string/permdesc_flashlight" />
+        android:description="@string/permdesc_flashlight"
+        android:protectionLevel="normal" />
 
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming -->
     <permission android:name="android.permission.WAKE_LOCK"
-        android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
-        android:protectionLevel="normal"
         android:label="@string/permlab_wakeLock"
-        android:description="@string/permdesc_wakeLock" />
+        android:description="@string/permdesc_wakeLock"
+        android:protectionLevel="normal" />
 
     <!-- Allows using the device's IR transmitter, if available -->
     <permission android:name="android.permission.TRANSMIT_IR"
-        android:permissionGroup="android.permission-group.AFFECTS_BATTERY"
-        android:protectionLevel="normal"
         android:label="@string/permlab_transmitIr"
-        android:description="@string/permdesc_transmitIr" />
+        android:description="@string/permdesc_transmitIr"
+        android:protectionLevel="normal" />
 
     <!-- ==================================================== -->
     <!-- Permissions related to changing audio settings   -->
     <!-- ==================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide direct access to speaker settings
-         the device. -->
-    <permission-group android:name="android.permission-group.AUDIO_SETTINGS"
-        android:label="@string/permgrouplab_audioSettings"
-        android:icon="@drawable/perm_group_audio_settings"
-        android:description="@string/permgroupdesc_audioSettings"
-        android:priority="130" />
-
     <!-- Allows an application to modify global audio settings -->
     <permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"
-        android:permissionGroup="android.permission-group.AUDIO_SETTINGS"
-        android:protectionLevel="normal"
         android:label="@string/permlab_modifyAudioSettings"
-        android:description="@string/permdesc_modifyAudioSettings" />
+        android:description="@string/permdesc_modifyAudioSettings"
+        android:protectionLevel="normal" />
 
     <!-- ================================== -->
     <!-- Permissions for accessing hardware -->
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that provide direct access to the hardware on
-         the device.  This includes audio, the camera, vibrator, etc. -->
-    <permission-group android:name="android.permission-group.HARDWARE_CONTROLS"
-        android:label="@string/permgrouplab_hardwareControls"
-        android:description="@string/permgroupdesc_hardwareControls"
-        android:priority="260"/>
-
     <!-- @SystemApi Allows an application to manage preferences and permissions for USB devices
          @hide -->
     <permission android:name="android.permission.MANAGE_USB"
-        android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_manageUsb"
-        android:description="@string/permdesc_manageUsb" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to access the MTP USB kernel driver.
          For use only by the device side MTP implementation.
          @hide -->
     <permission android:name="android.permission.ACCESS_MTP"
-        android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_accessMtp"
-        android:description="@string/permdesc_accessMtp" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows access to hardware peripherals.  Intended only for hardware testing.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.HARDWARE_TEST"
-        android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_hardware_test"
-        android:description="@string/permdesc_hardware_test" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows access to FM
          @hide This is not a third-party API (intended for system apps).-->
     <permission android:name="android.permission.ACCESS_FM_RADIO"
-        android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_fm"
-        android:description="@string/permdesc_fm" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows access to configure network interfaces, configure/use IPSec, etc.
          @hide -->
     <permission android:name="android.permission.NET_ADMIN"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />
 
     <!-- Allows registration for remote audio playback. @hide -->
     <permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
@@ -1152,219 +1118,89 @@
     <!-- @hide Allows enabling/disabling OEM unlock
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.OEM_UNLOCK_STATE"
-                android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Allows querying state of PersistentDataBlock
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCESS_PDB_STATE"
-                android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-                android:protectionLevel="signature" />
-
-
-    <!-- =========================================== -->
-    <!-- Permissions associated with audio capture -->
-    <!-- =========================================== -->
-    <eat-comment />
-
-    <!-- Used for permissions that are associated with accessing
-         microphone audio from the device. Note that phone calls also capture audio
-         but are in a separate (more visible) permission group. -->
-    <permission-group android:name="android.permission-group.MICROPHONE"
-        android:label="@string/permgrouplab_microphone"
-        android:icon="@drawable/perm_group_microphone"
-        android:description="@string/permgroupdesc_microphone"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="340" />
-
-    <!-- Allows an application to record audio -->
-    <permission android:name="android.permission.RECORD_AUDIO"
-        android:permissionGroup="android.permission-group.MICROPHONE"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_recordAudio"
-        android:description="@string/permdesc_recordAudio" />
-
+        android:protectionLevel="signature" />
 
     <!-- =========================================== -->
     <!-- Permissions associated with camera and image capture -->
     <!-- =========================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that are associated with accessing
-         camera or capturing images/video from the device. -->
-    <permission-group android:name="android.permission-group.CAMERA"
-        android:label="@string/permgrouplab_camera"
-        android:icon="@drawable/perm_group_camera"
-        android:description="@string/permgroupdesc_camera"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="350" />
-
-    <!-- Required to be able to access the camera device.
-         <p>This will automatically enforce the <a
-         href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code
-         &lt;uses-feature&gt;}</a> manifest element for <em>all</em> camera features.
-         If you do not require all camera features or can properly operate if a camera
-         is not available, then you must modify your manifest as appropriate in order to
-         install on devices that don't support all camera features.</p> -->
-    <permission android:name="android.permission.CAMERA"
-        android:permissionGroup="android.permission-group.CAMERA"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_camera"
-        android:description="@string/permdesc_camera" />
-
     <!-- @SystemApi Allows disabling the transmit-indicator LED that is normally on when
          a camera is in use by an application.
          @hide -->
     <permission android:name="android.permission.CAMERA_DISABLE_TRANSMIT_LED"
-        android:permissionGroup="android.permission-group.CAMERA"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_cameraDisableTransmitLed"
-        android:description="@string/permdesc_cameraDisableTransmitLed" />
+        android:protectionLevel="signature|system" />
+
+    <!-- Allows sending the camera service notifications about system-wide events.
+        @hide -->
+    <permission android:name="android.permission.CAMERA_SEND_SYSTEM_EVENTS"
+        android:protectionLevel="signature|system" />
 
     <!-- =========================================== -->
     <!-- Permissions associated with telephony state -->
     <!-- =========================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that are associated with accessing and modifying
-         telephony state: placing calls, intercepting outgoing calls, reading
-         and modifying the phone state. -->
-    <permission-group android:name="android.permission-group.PHONE_CALLS"
-        android:label="@string/permgrouplab_phoneCalls"
-        android:icon="@drawable/perm_group_phone_calls"
-        android:description="@string/permgroupdesc_phoneCalls"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="370" />
-
-    <!-- Allows an application to see the number being dialed during an outgoing
-         call with the option to redirect the call to a different number or
-         abort the call altogether. -->
-    <permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_processOutgoingCalls"
-        android:description="@string/permdesc_processOutgoingCalls" />
-
     <!-- @SystemApi Allows modification of the telephony state - power on, mmi, etc.
          Does not include placing calls.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MODIFY_PHONE_STATE"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_modifyPhoneState"
-        android:description="@string/permdesc_modifyPhoneState" />
-
-    <!-- Allows read only access to phone state.
-         <p class="note"><strong>Note:</strong> If <em>both</em> your <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-         minSdkVersion}</a> and <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
-         grants your app this permission. If you don't need this permission, be sure your <a
-         href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-         targetSdkVersion}</a> is 4 or higher. -->
-    <permission android:name="android.permission.READ_PHONE_STATE"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_readPhoneState"
-        android:description="@string/permdesc_readPhoneState" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows read only access to precise phone state.
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_readPrecisePhoneState"
-        android:description="@string/permdesc_readPrecisePhoneState" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows read access to privileged phone state.
          @hide Used internally. -->
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
         android:protectionLevel="signature|system" />
 
-     <!-- Allows an application to initiate a phone call without going through
-         the Dialer user interface for the user to confirm the call
-         being placed. -->
-    <permission android:name="android.permission.CALL_PHONE"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="dangerous"
-        android:permissionFlags="costsMoney"
-        android:label="@string/permlab_callPhone"
-        android:description="@string/permdesc_callPhone" />
-
-    <!-- Allows an application to use SIP service -->
-    <permission android:name="android.permission.USE_SIP"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="dangerous"
-        android:description="@string/permdesc_use_sip"
-        android:label="@string/permlab_use_sip" />
-
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
          corresponds to a device SIM.
          @hide -->
     <permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="system|signature"
-        android:description="@string/permdesc_register_sim_subscription"
-        android:label="@string/permlab_register_sim_subscription" />
+        android:protectionLevel="system|signature" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_CALL_PROVIDER.
          @hide -->
     <permission android:name="android.permission.REGISTER_CALL_PROVIDER"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="system|signature"
-        android:description="@string/permdesc_register_call_provider"
-        android:label="@string/permlab_register_call_provider" />
+        android:protectionLevel="system|signature" />
 
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_CONNECTION_MANAGER
          @hide -->
     <permission android:name="android.permission.REGISTER_CONNECTION_MANAGER"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="system|signature"
-        android:description="@string/permdesc_connection_manager"
-        android:label="@string/permlab_connection_manager" />
+        android:protectionLevel="system|signature" />
 
     <!-- @SystemApi Allows an application to bind to InCallService implementations.
          @hide -->
     <permission android:name="android.permission.BIND_INCALL_SERVICE"
-        android:permissionGroup="android.permission-group.PHONE_CALLS"
-        android:protectionLevel="system|signature"
-        android:description="@string/permdesc_bind_incall_service"
-        android:label="@string/permlab_bind_incall_service" />
+        android:protectionLevel="system|signature" />
 
     <!-- @SystemApi Allows an application to bind to ConnectionService implementations.
          @hide -->
     <permission android:name="android.permission.BIND_CONNECTION_SERVICE"
-                android:permissionGroup="android.permission-group.PHONE_CALLS"
-                android:protectionLevel="system|signature"
-                android:description="@string/permdesc_bind_connection_service"
-                android:label="@string/permlab_bind_connection_service" />
+        android:protectionLevel="system|signature" />
 
     <!-- @SystemApi Allows an application to control the in-call experience.
          @hide -->
     <permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
-                android:permissionGroup="android.permission-group.PHONE_CALLS"
-                android:protectionLevel="system|signature"
-                android:description="@string/permdesc_control_incall_experience"
-                android:label="@string/permlab_control_incall_experience" />
+        android:protectionLevel="system|signature" />
 
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Group of permissions that are related to SD card access. -->
-    <permission-group android:name="android.permission-group.STORAGE"
-        android:label="@string/permgrouplab_storage"
-        android:icon="@drawable/perm_group_storage"
-        android:description="@string/permgroupdesc_storage"
-        android:permissionGroupFlags="personalInfo"
-        android:priority="240" />
-
     <!-- Allows an application to read from external storage.
          <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
          granted this permission.</p>
@@ -1386,7 +1222,6 @@
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 4 or higher.-->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
-        android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardRead"
         android:description="@string/permdesc_sdcardRead"
         android:protectionLevel="normal" />
@@ -1405,25 +1240,18 @@
          {@link android.content.Context#getExternalFilesDir} and
          {@link android.content.Context#getExternalCacheDir}. -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
-        android:permissionGroup="android.permission-group.STORAGE"
         android:label="@string/permlab_sdcardWrite"
         android:description="@string/permdesc_sdcardWrite"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to write to internal media storage
          @hide  -->
     <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
-        android:permissionGroup="android.permission-group.STORAGE"
-        android:label="@string/permlab_mediaStorageWrite"
-        android:description="@string/permdesc_mediaStorageWrite"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to manage access to documents, usually as part
          of a document picker. -->
     <permission android:name="android.permission.MANAGE_DOCUMENTS"
-        android:permissionGroup="android.permission-group.STORAGE"
-        android:label="@string/permlab_manageDocs"
-        android:description="@string/permdesc_manageDocs"
         android:protectionLevel="signature" />
 
     <!-- ================================== -->
@@ -1431,41 +1259,22 @@
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Group of permissions that are related to the screenlock. -->
-    <permission-group android:name="android.permission-group.SCREENLOCK"
-        android:label="@string/permgrouplab_screenlock"
-        android:icon="@drawable/perm_group_screenlock"
-        android:permissionGroupFlags="personalInfo"
-        android:description="@string/permgroupdesc_screenlock"
-        android:priority="230" />
-
-    <!-- Allows applications to disable the keyguard -->
+    <!-- Allows applications to disable the keyguard if it is not secure. -->
     <permission android:name="android.permission.DISABLE_KEYGUARD"
-        android:permissionGroup="android.permission-group.SCREENLOCK"
-        android:protectionLevel="dangerous"
         android:description="@string/permdesc_disableKeyguard"
-        android:label="@string/permlab_disableKeyguard" />
+        android:label="@string/permlab_disableKeyguard"
+        android:protectionLevel="dangerous" />
 
     <!-- ================================== -->
     <!-- Permissions to access other installed applications  -->
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Group of permissions that are related to the other applications
-         installed on the system.  Examples include such as listing
-         running apps, or killing background processes. -->
-    <permission-group android:name="android.permission-group.APP_INFO"
-        android:label="@string/permgrouplab_appInfo"
-        android:icon="@drawable/perm_group_app_info"
-        android:description="@string/permgroupdesc_appInfo"
-        android:priority="220" />
-
     <!-- @deprecated No longer enforced. -->
     <permission android:name="android.permission.GET_TASKS"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="normal"
         android:label="@string/permlab_getTasks"
-        android:description="@string/permdesc_getTasks" />
+        android:description="@string/permdesc_getTasks"
+        android:protectionLevel="normal" />
 
     <!-- New version of GET_TASKS that apps can request, since GET_TASKS doesn't really
          give access to task information.  We need this new one because there are
@@ -1478,196 +1287,130 @@
          @hide
          @SystemApi -->
     <permission android:name="android.permission.REAL_GET_TASKS"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_getTasks"
-        android:description="@string/permdesc_getTasks" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to start a task from a ActivityManager#RecentTaskInfo.
          @hide -->
     <permission android:name="android.permission.START_TASKS_FROM_RECENTS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_startTasksFromRecents"
-        android:description="@string/permdesc_startTasksFromRecents" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi @hide Allows an application to call APIs that allow it to do interactions
          across the users on the device, using singleton services and
          user-targeted broadcasts.  This permission is not available to
          third party applications. -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_interactAcrossUsers"
-        android:description="@string/permdesc_interactAcrossUsers" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
          that removes restrictions on where broadcasts can be sent and allows other
          types of interactions. -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_interactAcrossUsersFull"
-        android:description="@string/permdesc_interactAcrossUsersFull" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
          users on the device. This permission is not available to
          third party applications. -->
     <permission android:name="android.permission.MANAGE_USERS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_manageUsers"
-        android:description="@string/permdesc_manageUsers" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to get full detailed information about
          recently running tasks, with full fidelity to the real state.
          @hide -->
     <permission android:name="android.permission.GET_DETAILED_TASKS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_getDetailedTasks"
-        android:description="@string/permdesc_getDetailedTasks" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to change the Z-order of tasks -->
     <permission android:name="android.permission.REORDER_TASKS"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="normal"
         android:label="@string/permlab_reorderTasks"
-        android:description="@string/permdesc_reorderTasks" />
+        android:description="@string/permdesc_reorderTasks"
+        android:protectionLevel="normal" />
 
     <!-- @hide Allows an application to change to remove/kill tasks -->
     <permission android:name="android.permission.REMOVE_TASKS"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_removeTasks"
-        android:description="@string/permdesc_removeTasks" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi @hide Allows an application to create/manage/remove stacks -->
     <permission android:name="android.permission.MANAGE_ACTIVITY_STACKS"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_manageActivityStacks"
-        android:description="@string/permdesc_manageActivityStacks" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows an application to start any activity, regardless of permission
-         protection or exported state. @hide -->
+         protection or exported state.
+         @hide -->
     <permission android:name="android.permission.START_ANY_ACTIVITY"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_startAnyActivity"
-        android:description="@string/permdesc_startAnyActivity" />
+        android:protectionLevel="signature" />
 
     <!-- @deprecated The {@link android.app.ActivityManager#restartPackage}
         API is no longer supported. -->
     <permission android:name="android.permission.RESTART_PACKAGES"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="normal"
         android:label="@string/permlab_killBackgroundProcesses"
-        android:description="@string/permdesc_killBackgroundProcesses" />
+        android:description="@string/permdesc_killBackgroundProcesses"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to call
         {@link android.app.ActivityManager#killBackgroundProcesses}. -->
     <permission android:name="android.permission.KILL_BACKGROUND_PROCESSES"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="normal"
         android:label="@string/permlab_killBackgroundProcesses"
-        android:description="@string/permdesc_killBackgroundProcesses" />
+        android:description="@string/permdesc_killBackgroundProcesses"
+        android:protectionLevel="normal" />
 
     <!-- ================================== -->
     <!-- Permissions affecting the display of other applications  -->
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Group of permissions that allow manipulation of how
-         another application displays UI to the user. -->
-    <permission-group android:name="android.permission-group.DISPLAY"
-        android:label="@string/permgrouplab_display"
-        android:icon="@drawable/perm_group_display"
-        android:description="@string/permgroupdesc_display"
-        android:priority="190"/>
-
     <!-- Allows an application to open windows using the type
          {@link android.view.WindowManager.LayoutParams#TYPE_SYSTEM_ALERT},
          shown on top of all other applications.  Very few applications
          should use this permission; these windows are intended for
          system-level interaction with the user. -->
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
-        android:permissionGroup="android.permission-group.DISPLAY"
-        android:protectionLevel="dangerous"
         android:label="@string/permlab_systemAlertWindow"
-        android:description="@string/permdesc_systemAlertWindow" />
+        android:description="@string/permdesc_systemAlertWindow"
+        android:protectionLevel="dangerous" />
 
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
     <!-- ================================== -->
     <eat-comment />
 
-    <!-- Group of permissions that allow manipulation of how
-         another application displays UI to the user. -->
-    <permission-group android:name="android.permission-group.WALLPAPER"
-        android:label="@string/permgrouplab_wallpaper"
-        android:icon="@drawable/perm_group_wallpaper"
-        android:description="@string/permgroupdesc_wallpaper"
-        android:priority="150" />
-
     <!-- Allows applications to set the wallpaper -->
     <permission android:name="android.permission.SET_WALLPAPER"
-        android:permissionGroup="android.permission-group.WALLPAPER"
-        android:protectionLevel="normal"
         android:label="@string/permlab_setWallpaper"
-        android:description="@string/permdesc_setWallpaper" />
+        android:description="@string/permdesc_setWallpaper"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to set the wallpaper hints -->
     <permission android:name="android.permission.SET_WALLPAPER_HINTS"
-        android:permissionGroup="android.permission-group.WALLPAPER"
-        android:protectionLevel="normal"
         android:label="@string/permlab_setWallpaperHints"
-        android:description="@string/permdesc_setWallpaperHints" />
+        android:description="@string/permdesc_setWallpaperHints"
+        android:protectionLevel="normal" />
 
     <!-- ============================================ -->
     <!-- Permissions for changing the system clock -->
     <!-- ============================================ -->
     <eat-comment />
 
-    <!-- Group of permissions that are related to system clock. -->
-    <permission-group android:name="android.permission-group.SYSTEM_CLOCK"
-        android:label="@string/permgrouplab_systemClock"
-        android:icon="@drawable/perm_group_system_clock"
-        android:description="@string/permgroupdesc_systemClock"
-        android:priority="140" />
-
     <!-- @SystemApi Allows applications to set the system time.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_TIME"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_setTime"
-        android:description="@string/permdesc_setTime" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows applications to set the system time zone -->
     <permission android:name="android.permission.SET_TIME_ZONE"
-        android:permissionGroup="android.permission-group.SYSTEM_CLOCK"
-        android:protectionLevel="normal"
         android:label="@string/permlab_setTimeZone"
-        android:description="@string/permdesc_setTimeZone" />
+        android:description="@string/permdesc_setTimeZone"
+        android:protectionLevel="normal" />
 
     <!-- ==================================================== -->
     <!-- Permissions related to changing status bar   -->
     <!-- ==================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that change the status bar -->
-    <permission-group android:name="android.permission-group.STATUS_BAR"
-        android:label="@string/permgrouplab_statusBar"
-        android:icon="@drawable/perm_group_status_bar"
-        android:description="@string/permgroupdesc_statusBar"
-        android:priority="110" />
-
     <!-- Allows an application to expand or collapse the status bar. -->
     <permission android:name="android.permission.EXPAND_STATUS_BAR"
-        android:permissionGroup="android.permission-group.STATUS_BAR"
-        android:protectionLevel="normal"
         android:label="@string/permlab_expandStatusBar"
-        android:description="@string/permdesc_expandStatusBar" />
+        android:description="@string/permdesc_expandStatusBar"
+        android:protectionLevel="normal" />
 
     <!-- ============================================================== -->
     <!-- Permissions related to adding/removing shortcuts from Launcher -->
@@ -1675,54 +1418,39 @@
     <eat-comment />
 
     <!-- Allows an application to install a shortcut in Launcher -->
-    <permission
-        android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+    <permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"
         android:label="@string/permlab_install_shortcut"
-        android:description="@string/permdesc_install_shortcut" />
+        android:description="@string/permdesc_install_shortcut"
+        android:protectionLevel="dangerous"/>
 
-        <!-- Allows an application to uninstall a shortcut in Launcher -->
-    <permission
-        android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+    <!-- Allows an application to uninstall a shortcut in Launcher -->
+    <permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
         android:label="@string/permlab_uninstall_shortcut"
-        android:description="@string/permdesc_uninstall_shortcut"/>
+        android:description="@string/permdesc_uninstall_shortcut"
+        android:protectionLevel="dangerous"/>
 
     <!-- ==================================================== -->
     <!-- Permissions related to accessing sync settings   -->
     <!-- ==================================================== -->
     <eat-comment />
 
-    <!-- Used for permissions that access the sync settings or sync
-         related information. -->
-    <permission-group android:name="android.permission-group.SYNC_SETTINGS"
-        android:label="@string/permgrouplab_syncSettings"
-        android:icon="@drawable/perm_group_sync_settings"
-        android:description="@string/permgroupdesc_syncSettings"
-        android:priority="120" />
-
     <!-- Allows applications to read the sync settings -->
     <permission android:name="android.permission.READ_SYNC_SETTINGS"
-        android:permissionGroup="android.permission-group.SYNC_SETTINGS"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_readSyncSettings"
-        android:label="@string/permlab_readSyncSettings" />
+        android:label="@string/permlab_readSyncSettings"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to write the sync settings -->
     <permission android:name="android.permission.WRITE_SYNC_SETTINGS"
-        android:permissionGroup="android.permission-group.SYNC_SETTINGS"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_writeSyncSettings"
-        android:label="@string/permlab_writeSyncSettings" />
+        android:label="@string/permlab_writeSyncSettings"
+        android:protectionLevel="normal" />
 
     <!-- Allows applications to read the sync stats -->
     <permission android:name="android.permission.READ_SYNC_STATS"
-        android:permissionGroup="android.permission-group.SYNC_SETTINGS"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_readSyncStats"
-        android:label="@string/permlab_readSyncStats" />
+        android:label="@string/permlab_readSyncStats"
+        android:protectionLevel="normal" />
 
 
     <!-- ============================================ -->
@@ -1730,102 +1458,64 @@
     <!-- ============================================ -->
     <eat-comment />
 
-    <!-- Group of permissions that are related to system APIs.  Many
-         of these are not permissions the user will be expected to understand,
-         and such permissions should generally be marked as "normal" protection
-         level so they don't get displayed.  This can also, however, be used
-         for miscellaneous features that provide access to the operating system,
-         such as writing the global system settings. -->
-    <permission-group android:name="android.permission-group.SYSTEM_TOOLS"
-        android:label="@string/permgrouplab_systemTools"
-        android:icon="@drawable/perm_group_system_tools"
-        android:description="@string/permgroupdesc_systemTools"
-        android:priority="100" />
-
     <!-- @SystemApi @hide Change the screen compatibility mode of applications -->
     <permission android:name="android.permission.SET_SCREEN_COMPATIBILITY"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_setScreenCompatibility"
-        android:description="@string/permdesc_setScreenCompatibility" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to access all multi-user external storage @hide -->
     <permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:label="@string/permlab_sdcardAccessAll"
-        android:description="@string/permdesc_sdcardAccessAll"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to modify the current configuration, such
          as locale. -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_changeConfiguration"
-        android:description="@string/permdesc_changeConfiguration" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- Allows an application to read or write the system settings. -->
     <permission android:name="android.permission.WRITE_SETTINGS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="normal"
         android:label="@string/permlab_writeSettings"
-        android:description="@string/permdesc_writeSettings" />
+        android:description="@string/permdesc_writeSettings"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows an application to modify the Google service map.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_GSERVICES"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_writeGservices"
-        android:description="@string/permdesc_writeGservices" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
         @hide -->
     <permission android:name="android.permission.FORCE_STOP_PACKAGES"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_forceStopPackages"
-        android:description="@string/permdesc_forceStopPackages" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi @hide Allows an application to retrieve the content of the active window
          An active window is the window that has fired an accessibility event. -->
     <permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_retrieve_window_content"
-        android:description="@string/permdesc_retrieve_window_content" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Modify the global animation scaling factor.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_ANIMATION_SCALE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_setAnimationScale"
-        android:description="@string/permdesc_setAnimationScale" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @deprecated This functionality will be removed in the future; please do
          not use. Allow an application to make its activities persistent. -->
     <permission android:name="android.permission.PERSISTENT_ACTIVITY"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="normal"
         android:label="@string/permlab_persistentActivity"
-        android:description="@string/permdesc_persistentActivity" />
+        android:description="@string/permdesc_persistentActivity"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to find out the space used by any package. -->
     <permission android:name="android.permission.GET_PACKAGE_SIZE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="normal"
         android:label="@string/permlab_getPackageSize"
-        android:description="@string/permdesc_getPackageSize" />
+        android:description="@string/permdesc_getPackageSize"
+        android:protectionLevel="normal" />
 
     <!-- @deprecated No longer useful, see
          {@link android.content.pm.PackageManager#addPackageToPreferred}
          for details. -->
     <permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_setPreferredApplications"
-        android:description="@string/permdesc_setPreferredApplications" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to receive the
          {@link android.content.Intent#ACTION_BOOT_COMPLETED} that is
@@ -1839,143 +1529,91 @@
          explicitly declare your use of this facility to make that visible
          to the user. -->
     <permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
-        android:permissionGroup="android.permission-group.APP_INFO"
-        android:protectionLevel="normal"
         android:label="@string/permlab_receiveBootCompleted"
-        android:description="@string/permdesc_receiveBootCompleted" />
+        android:description="@string/permdesc_receiveBootCompleted"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to broadcast sticky intents.  These are
          broadcasts whose data is held by the system after being finished,
          so that clients can quickly retrieve that data without having
          to wait for the next broadcast. -->
     <permission android:name="android.permission.BROADCAST_STICKY"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="normal"
         android:label="@string/permlab_broadcastSticky"
-        android:description="@string/permdesc_broadcastSticky" />
+        android:description="@string/permdesc_broadcastSticky"
+        android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows mounting and unmounting file systems for removable storage.
     <p>Not for use by third-party applications.-->
     <permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="system|signature"
-        android:label="@string/permlab_mount_unmount_filesystems"
-        android:description="@string/permdesc_mount_unmount_filesystems" />
+        android:protectionLevel="system|signature" />
 
     <!-- @SystemApi Allows formatting file systems for removable storage.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="system|signature"
-        android:label="@string/permlab_mount_format_filesystems"
-        android:description="@string/permdesc_mount_format_filesystems" />
+        android:protectionLevel="system|signature" />
 
     <!-- Allows access to ASEC non-destructive API calls
          @hide  -->
     <permission android:name="android.permission.ASEC_ACCESS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_asec_access"
-        android:description="@string/permdesc_asec_access" />
+        android:protectionLevel="signature" />
 
     <!-- Allows creation of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_CREATE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_asec_create"
-        android:description="@string/permdesc_asec_create" />
+        android:protectionLevel="signature" />
 
     <!-- Allows destruction of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_DESTROY"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_asec_destroy"
-        android:description="@string/permdesc_asec_destroy" />
+        android:protectionLevel="signature" />
 
     <!-- Allows mount / unmount of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_asec_mount_unmount"
-        android:description="@string/permdesc_asec_mount_unmount" />
+        android:protectionLevel="signature" />
 
     <!-- Allows rename of ASEC volumes
          @hide  -->
     <permission android:name="android.permission.ASEC_RENAME"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_asec_rename"
-        android:description="@string/permdesc_asec_rename" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to write the apn settings.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
-                android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-                android:protectionLevel="signature|system"
-                android:description="@string/permdesc_writeApnSettings"
-                android:label="@string/permlab_writeApnSettings" />
-
-    <!-- Allows an application to allow access the subscribed feeds
-         ContentProvider. -->
-    <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:label="@string/permlab_subscribedFeedsRead"
-        android:description="@string/permdesc_subscribedFeedsRead"
-        android:protectionLevel="normal" />
-    <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:label="@string/permlab_subscribedFeedsWrite"
-        android:description="@string/permdesc_subscribedFeedsWrite"
-        android:protectionLevel="dangerous" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows applications to change network connectivity state -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:protectionLevel="normal"
         android:description="@string/permdesc_changeNetworkState"
-        android:label="@string/permlab_changeNetworkState" />
+        android:label="@string/permlab_changeNetworkState"
+        android:protectionLevel="normal" />
 
     <!-- Allows an application to clear the caches of all installed
          applications on the device.  -->
     <permission android:name="android.permission.CLEAR_APP_CACHE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_clearAppCache"
-        android:description="@string/permdesc_clearAppCache" />
+        android:protectionLevel="dangerous" />
 
     <!-- @SystemApi Allows an application to use any media decoder when decoding for playback
          @hide -->
     <permission android:name="android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_anyCodecForPlayback"
-        android:description="@string/permdesc_anyCodecForPlayback" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to install and/or uninstall CA certificates on
          behalf of the user.
          @hide -->
     <permission android:name="android.permission.MANAGE_CA_CERTIFICATES"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_manageCaCertificates"
-        android:description="@string/permdesc_manageCaCertificates" />
+        android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to do certain operations needed for
          interacting with the recovery (system update) system.
          @hide -->
     <permission android:name="android.permission.RECOVERY"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature|system"
-        android:label="@string/permlab_recovery"
-        android:description="@string/permdesc_recovery" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows the system to bind to an application's task services
          @hide -->
     <permission android:name="android.permission.BIND_JOB_SERVICE"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_bindJobService"
-        android:description="@string/permdesc_bindJobService" />
+        android:protectionLevel="signature" />
     <uses-permission android:name="android.permission.BIND_JOB_SERVICE"/>
 
     <!-- ========================================= -->
@@ -1983,152 +1621,100 @@
     <!-- ========================================= -->
     <eat-comment />
 
-    <!-- Group of permissions that are related to development features.  These
-         are not permissions that should appear in third-party applications; they
-         protect APIs that are intended only to be used for development
-         purposes. -->
-    <permission-group android:name="android.permission-group.DEVELOPMENT_TOOLS"
-        android:label="@string/permgrouplab_developmentTools"
-        android:description="@string/permgroupdesc_developmentTools"
-        android:priority="310" />
-
     <!-- @SystemApi Allows an application to read or write the secure system settings.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WRITE_SECURE_SETTINGS"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_writeSecureSettings"
-        android:description="@string/permdesc_writeSecureSettings" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allows an application to retrieve state dump information from system services.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DUMP"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_dump"
-        android:description="@string/permdesc_dump" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allows an application to read the low-level system log files.
     <p>Not for use by third-party applications, because
     Log entries can contain the user's private information. -->
     <permission android:name="android.permission.READ_LOGS"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_readLogs"
-        android:description="@string/permdesc_readLogs" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Configure an application for debugging.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_DEBUG_APP"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_setDebugApp"
-        android:description="@string/permdesc_setDebugApp" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allows an application to set the maximum number of (not needed)
          application processes that can be running.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_PROCESS_LIMIT"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_setProcessLimit"
-        android:description="@string/permdesc_setProcessLimit" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allows an application to control whether activities are immediately
          finished when put in the background.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_ALWAYS_FINISH"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_setAlwaysFinish"
-        android:description="@string/permdesc_setAlwaysFinish" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allow an application to request that a signal be sent to all persistent processes.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES"
-        android:permissionGroup="android.permission-group.DEVELOPMENT_TOOLS"
-        android:protectionLevel="signature|system|development"
-        android:label="@string/permlab_signalPersistentProcesses"
-        android:description="@string/permdesc_signalPersistentProcesses" />
+        android:protectionLevel="signature|system|development" />
 
     <!-- ==================================== -->
-    <!-- Private (signature-only) permissions -->
+    <!-- Private permissions                  -->
     <!-- ==================================== -->
     <eat-comment />
 
     <!-- @SystemApi Allows applications to RW to diagnostic resources.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DIAGNOSTIC"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:description="@string/permdesc_diagnostic"
-        android:label="@string/permlab_diagnostic" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to open, close, or disable the status bar
          and its icons.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.STATUS_BAR"
-        android:label="@string/permlab_statusBar"
-        android:description="@string/permdesc_statusBar"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
     @hide -->
     <permission android:name="android.permission.STATUS_BAR_SERVICE"
-        android:label="@string/permlab_statusBarService"
-        android:description="@string/permdesc_statusBarService"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to force a BACK operation on whatever is the
          top activity.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.FORCE_BACK"
-        android:label="@string/permlab_forceBack"
-        android:description="@string/permdesc_forceBack"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to update device statistics.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.UPDATE_DEVICE_STATS"
-        android:label="@string/permlab_updateBatteryStats"
-        android:description="@string/permdesc_updateBatteryStats"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi @hide Allows an application to collect battery statistics -->
     <permission android:name="android.permission.GET_APP_OPS_STATS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:label="@string/permlab_getAppOpsStats"
-        android:description="@string/permdesc_getAppOpsStats"
         android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allows an application to update application operation statistics. Not for
          use by third party apps. @hide -->
     <permission android:name="android.permission.UPDATE_APP_OPS_STATS"
-        android:label="@string/permlab_updateAppOpsStats"
-        android:description="@string/permdesc_updateAppOpsStats"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to open windows that are for use by parts
          of the system user interface.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"
-        android:label="@string/permlab_internalSystemWindow"
-        android:description="@string/permdesc_internalSystemWindow"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to manage (create, destroy,
          Z-order) application tokens in the window manager.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MANAGE_APP_TOKENS"
-        android:label="@string/permlab_manageAppTokens"
-        android:description="@string/permdesc_manageAppTokens"
         android:protectionLevel="signature" />
 
     <!-- @hide Allows the application to temporarily freeze the screen for a
          full-screen transition. -->
     <permission android:name="android.permission.FREEZE_SCREEN"
-        android:label="@string/permlab_freezeScreen"
-        android:description="@string/permdesc_freezeScreen"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to inject user events (keys, touch, trackball)
@@ -2136,33 +1722,23 @@
          permission, you can only deliver events to windows in your own process.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INJECT_EVENTS"
-        android:label="@string/permlab_injectEvents"
-        android:description="@string/permdesc_injectEvents"
         android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to register an input filter which filters the stream
          of user events (keys, touch, trackball) before they are dispatched to any window. -->
     <permission android:name="android.permission.FILTER_EVENTS"
-        android:label="@string/permlab_filter_events"
-        android:description="@string/permdesc_filter_events"
         android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to retrieve the window token from the accessibility manager. -->
     <permission android:name="android.permission.RETRIEVE_WINDOW_TOKEN"
-        android:label="@string/permlab_retrieveWindowToken"
-        android:description="@string/permdesc_retrieveWindowToken"
         android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to collect frame statistics -->
     <permission android:name="android.permission.FRAME_STATS"
-         android:label="@string/permlab_frameStats"
-         android:description="@string/permdesc_frameStats"
          android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to temporary enable accessibility on the device. -->
     <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
-        android:label="@string/permlab_temporary_enable_accessibility"
-        android:description="@string/permdesc_temporary_enable_accessibility"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to watch and control how activities are
@@ -2170,16 +1746,12 @@
          (usually the monkey command).
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_ACTIVITY_WATCHER"
-        android:label="@string/permlab_runSetActivityWatcher"
-        android:description="@string/permdesc_runSetActivityWatcher"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to call the activity manager shutdown() API
          to put the higher-level system there into a shutdown state.
          @hide -->
     <permission android:name="android.permission.SHUTDOWN"
-        android:label="@string/permlab_shutdown"
-        android:description="@string/permdesc_shutdown"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to tell the activity manager to temporarily
@@ -2188,16 +1760,12 @@
          critical UI such as the home screen.
          @hide -->
     <permission android:name="android.permission.STOP_APP_SWITCHES"
-        android:label="@string/permlab_stopAppSwitches"
-        android:description="@string/permdesc_stopAppSwitches"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to retrieve private information about
          the current top activity, such as any assist context it can provide.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
-        android:label="@string/permlab_getTopActivityInfo"
-        android:description="@string/permdesc_getTopActivityInfo"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to retrieve the current state of keys and
@@ -2205,235 +1773,171 @@
          <p>Not for use by third-party applications.
          @deprecated The API that used this permission has been removed. -->
     <permission android:name="android.permission.READ_INPUT_STATE"
-        android:label="@string/permlab_readInputState"
-        android:description="@string/permdesc_readInputState"
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.inputmethodservice.InputMethodService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_INPUT_METHOD"
-        android:label="@string/permlab_bindInputMethod"
-        android:description="@string/permdesc_bindInputMethod"
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.accessibilityservice.AccessibilityService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
-        android:label="@string/permlab_bindAccessibilityService"
-        android:description="@string/permdesc_bindAccessibilityService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.printservice.PrintService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_PRINT_SERVICE"
-        android:label="@string/permlab_bindPrintService"
-        android:description="@string/permdesc_bindPrintService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.nfc.cardemulation.HostApduService}
          or {@link android.nfc.cardemulation.OffHostApduService} to ensure that only
          the system can bind to it. -->
     <permission android:name="android.permission.BIND_NFC_SERVICE"
-        android:label="@string/permlab_bindNfcService"
-        android:description="@string/permdesc_bindNfcService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by the PrintSpooler to ensure that only the system can bind to it.
          @hide -->
     <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
-        android:label="@string/permlab_bindPrintSpoolerService"
-        android:description="@string/permdesc_bindPrintSpoolerService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a TextService (e.g. SpellCheckerService)
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_TEXT_SERVICE"
-        android:label="@string/permlab_bindTextService"
-        android:description="@string/permdesc_bindTextService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.net.VpnService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_VPN_SERVICE"
-        android:label="@string/permlab_bindVpnService"
-        android:description="@string/permdesc_bindVpnService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.service.wallpaper.WallpaperService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_WALLPAPER"
-        android:label="@string/permlab_bindWallpaper"
-        android:description="@string/permdesc_bindWallpaper"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link android.service.voice.VoiceInteractionService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_VOICE_INTERACTION"
-        android:label="@string/permlab_bindVoiceInteraction"
-        android:description="@string/permdesc_bindVoiceInteraction"
         android:protectionLevel="signature" />
 
     <!-- Must be required by hotword enrollment application,
          to ensure that only the system can interact with it.
          @hide <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_VOICE_KEYPHRASES"
-        android:label="@string/permlab_manageVoiceKeyphrases"
-        android:description="@string/permdesc_manageVoiceKeyphrases"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link com.android.media.remotedisplay.RemoteDisplayProvider},
          to ensure that only the system can bind to it.
          @hide -->
     <permission android:name="android.permission.BIND_REMOTE_DISPLAY"
-        android:label="@string/permlab_bindRemoteDisplay"
-        android:description="@string/permdesc_bindRemoteDisplay"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.media.tv.TvInputService}
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_TV_INPUT"
-        android:label="@string/permlab_bindTvInput"
-        android:description="@string/permdesc_bindTvInput"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to modify parental controls
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
-        android:label="@string/permlab_modifyParentalControls"
-        android:description="@string/permdesc_modifyParentalControls"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link android.media.routing.MediaRouteService}
          to ensure that only the system can interact with it.
          @hide -->
     <permission android:name="android.permission.BIND_ROUTE_PROVIDER"
-        android:label="@string/permlab_bindRouteProvider"
-        android:description="@string/permdesc_bindRouteProvider"
         android:protectionLevel="signature" />
 
     <!-- Must be required by device administration receiver, to ensure that only the
          system can interact with it. -->
     <permission android:name="android.permission.BIND_DEVICE_ADMIN"
-        android:label="@string/permlab_bindDeviceAdmin"
-        android:description="@string/permdesc_bindDeviceAdmin"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Required to add or remove another application as a device admin.
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.MANAGE_DEVICE_ADMINS"
-        android:label="@string/permlab_manageDeviceAdmins"
-        android:description="@string/permdesc_manageDeviceAdmins"
         android:protectionLevel="signature|system" />
 
     <!-- Allows low-level access to setting the orientation (actually
          rotation) of the screen.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_ORIENTATION"
-        android:label="@string/permlab_setOrientation"
-        android:description="@string/permdesc_setOrientation"
         android:protectionLevel="signature" />
 
     <!-- Allows low-level access to setting the pointer speed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.SET_POINTER_SPEED"
-        android:label="@string/permlab_setPointerSpeed"
-        android:description="@string/permdesc_setPointerSpeed"
         android:protectionLevel="signature" />
 
     <!-- Allows low-level access to setting input device calibration.
          <p>Not for use by normal applications.
          @hide -->
     <permission android:name="android.permission.SET_INPUT_CALIBRATION"
-        android:label="@string/permlab_setInputCalibration"
-        android:description="@string/permdesc_setInputCalibration"
         android:protectionLevel="signature" />
 
     <!-- Allows low-level access to setting the keyboard layout.
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
-        android:label="@string/permlab_setKeyboardLayout"
-        android:description="@string/permdesc_setKeyboardLayout"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to install packages.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INSTALL_PACKAGES"
-        android:label="@string/permlab_installPackages"
-        android:description="@string/permdesc_installPackages"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to clear user data.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CLEAR_APP_USER_DATA"
-        android:label="@string/permlab_clearAppUserData"
-        android:description="@string/permdesc_clearAppUserData"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to delete cache files.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
-        android:label="@string/permlab_deleteCacheFiles"
-        android:description="@string/permdesc_deleteCacheFiles"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to delete packages.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DELETE_PACKAGES"
-        android:label="@string/permlab_deletePackages"
-        android:description="@string/permdesc_deletePackages"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to move location of installed package.
          @hide -->
     <permission android:name="android.permission.MOVE_PACKAGE"
-        android:label="@string/permlab_movePackage"
-        android:description="@string/permdesc_movePackage"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to change whether an application component (other than its own) is
          enabled or not.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
-        android:label="@string/permlab_changeComponentState"
-        android:description="@string/permdesc_changeComponentState"
         android:protectionLevel="signature|system" />
 
     <!-- @hide Allows an application to grant or revoke specific permissions. -->
     <permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS"
-        android:label="@string/permlab_grantRevokePermissions"
-        android:description="@string/permdesc_grantRevokePermissions"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to use SurfaceFlinger's low level features.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
-        android:label="@string/permlab_accessSurfaceFlinger"
-        android:description="@string/permdesc_accessSurfaceFlinger"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to take screen shots and more generally
          get access to the frame buffer data.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_FRAME_BUFFER"
-        android:label="@string/permlab_readFrameBuffer"
-        android:description="@string/permdesc_readFrameBuffer"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to use InputFlinger's low level features.
          @hide -->
     <permission android:name="android.permission.ACCESS_INPUT_FLINGER"
-        android:label="@string/permlab_accessInputFlinger"
-        android:description="@string/permdesc_accessInputFlinger"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to configure and connect to Wifi displays
          @hide -->
     <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
-        android:label="@string/permlab_configureWifiDisplay"
-        android:description="@string/permdesc_configureWifiDisplay"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to control low-level features of Wifi displays
@@ -2441,141 +1945,100 @@
          by the display manager.
          @hide -->
     <permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
-        android:label="@string/permlab_controlWifiDisplay"
-        android:description="@string/permdesc_controlWifiDisplay"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to control VPN.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.CONTROL_VPN"
-        android:label="@string/permlab_controlVpn"
-        android:description="@string/permdesc_controlVpn"
         android:protectionLevel="signature|system" />
     <uses-permission android:name="android.permission.CONTROL_VPN" />
 
     <!-- @SystemApi Allows an application to capture audio output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
-        android:label="@string/permlab_captureAudioOutput"
-        android:description="@string/permdesc_captureAudioOutput"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to capture audio for hotword detection.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.CAPTURE_AUDIO_HOTWORD"
-        android:label="@string/permlab_captureAudioHotword"
-        android:description="@string/permdesc_captureAudioHotword"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to modify audio routing and override policy decisions.
          <p>Not for use by third-party applications.</p>
          @hide -->
     <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
-        android:label="@string/permlab_modifyAudioRouting"
-        android:description="@string/permdesc_modifyAudioRouting"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to capture video output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT"
-        android:label="@string/permlab_captureVideoOutput"
-        android:description="@string/permdesc_captureVideoOutput"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to capture secure video output.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT"
-        android:label="@string/permlab_captureSecureVideoOutput"
-        android:description="@string/permdesc_captureSecureVideoOutput"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to know what content is playing and control its playback.
          <p>Not for use by third-party applications due to privacy of media consumption</p>  -->
     <permission android:name="android.permission.MEDIA_CONTENT_CONTROL"
-        android:label="@string/permlab_mediaContentControl"
-        android:description="@string/permdesc_mediaContentControl"
         android:protectionLevel="signature|system" />
 
     <!-- Required to be able to disable the device (very dangerous!).
     <p>Not for use by third-party applications.. -->
     <permission android:name="android.permission.BRICK"
-        android:label="@string/permlab_brick"
-        android:description="@string/permdesc_brick"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Required to be able to reboot the device.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.REBOOT"
-        android:label="@string/permlab_reboot"
-        android:description="@string/permdesc_reboot"
         android:protectionLevel="signature|system" />
 
    <!-- Allows low-level access to power management.
    <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DEVICE_POWER"
-        android:label="@string/permlab_devicePower"
-        android:description="@string/permdesc_devicePower"
         android:protectionLevel="signature" />
 
    <!-- Allows access to the PowerManager.userActivity function.
    <p>Not for use by third-party applications. @hide @SystemApi -->
     <permission android:name="android.permission.USER_ACTIVITY"
-        android:label="@string/permlab_userActivity"
-        android:description="@string/permdesc_userActivity"
         android:protectionLevel="signature|system" />
 
    <!-- @hide Allows low-level access to tun tap driver -->
     <permission android:name="android.permission.NET_TUNNELING"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />
 
     <!-- Run as a manufacturer test application, running as the root user.
          Only available when the device is running in manufacturer test mode.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.FACTORY_TEST"
-        android:label="@string/permlab_factoryTest"
-        android:description="@string/permdesc_factoryTest"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a notification that an application
          package has been removed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BROADCAST_PACKAGE_REMOVED"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:label="@string/permlab_broadcastPackageRemoved"
-        android:description="@string/permdesc_broadcastPackageRemoved"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast an SMS receipt notification.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BROADCAST_SMS"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:label="@string/permlab_broadcastSmsReceived"
-        android:description="@string/permdesc_broadcastSmsReceived"
         android:protectionLevel="signature" />
 
     <!-- Allows an application to broadcast a WAP PUSH receipt notification.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BROADCAST_WAP_PUSH"
-        android:permissionGroup="android.permission-group.MESSAGES"
-        android:label="@string/permlab_broadcastWapPush"
-        android:description="@string/permdesc_broadcastWapPush"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to broadcast privileged networking requests.
          <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.BROADCAST_NETWORK_PRIVILEGED"
-        android:permissionGroup="android.permission-group.NETWORK"
-        android:label="@string/permlab_broadcastNetworkPrivileged"
-        android:description="@string/permdesc_broadcastNetworkPrivileged"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Not for use by third-party applications. -->
     <permission android:name="android.permission.MASTER_CLEAR"
-        android:label="@string/permlab_masterClear"
-        android:description="@string/permdesc_masterClear"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to call any phone number, including emergency
@@ -2583,69 +2046,54 @@
          to confirm the call being placed.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CALL_PRIVILEGED"
-        android:label="@string/permlab_callPrivileged"
-        android:description="@string/permdesc_callPrivileged"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to perform CDMA OTA provisioning @hide -->
     <permission android:name="android.permission.PERFORM_CDMA_PROVISIONING"
-        android:label="@string/permlab_performCdmaProvisioning"
-        android:description="@string/permdesc_performCdmaProvisioning"
+        android:protectionLevel="signature|system" />
+
+    <!-- @SystemApi Allows an application to perform SIM Activation @hide -->
+    <permission android:name="android.permission.PERFORM_SIM_ACTIVATION"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows enabling/disabling location update notifications from
          the radio.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.CONTROL_LOCATION_UPDATES"
-        android:label="@string/permlab_locationUpdates"
-        android:description="@string/permdesc_locationUpdates"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows read/write access to the "properties" table in the checkin
          database, to change values that get uploaded.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"
-        android:label="@string/permlab_checkinProperties"
-        android:description="@string/permdesc_checkinProperties"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to collect component usage
          statistics
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
-        android:label="@string/permlab_pkgUsageStats"
-        android:description="@string/permdesc_pkgUsageStats"
         android:protectionLevel="signature|development|appop" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
     <!-- @SystemApi Allows an application to collect battery statistics -->
     <permission android:name="android.permission.BATTERY_STATS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:label="@string/permlab_batteryStats"
-        android:description="@string/permdesc_batteryStats"
         android:protectionLevel="signature|system|development" />
 
     <!-- @SystemApi Allows an application to control the backup and restore process.
     <p>Not for use by third-party applications.
          @hide pending API council -->
     <permission android:name="android.permission.BACKUP"
-        android:label="@string/permlab_backup"
-        android:description="@string/permdesc_backup"
         android:protectionLevel="signature|system" />
 
     <!-- Allows a package to launch the secure full-backup confirmation UI.
          ONLY the system process may hold this permission.
          @hide -->
     <permission android:name="android.permission.CONFIRM_FULL_BACKUP"
-        android:label="@string/permlab_confirm_full_backup"
-        android:description="@string/permdesc_confirm_full_backup"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Must be required by a {@link android.widget.RemoteViewsService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_REMOTEVIEWS"
-        android:label="@string/permlab_bindRemoteViews"
-        android:description="@string/permdesc_bindRemoteViews"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to tell the AppWidget service which application
@@ -2655,33 +2103,25 @@
          An application that has this permission should honor that contract.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BIND_APPWIDGET"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
-        android:label="@string/permlab_bindGadget"
-        android:description="@string/permdesc_bindGadget"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Private permission, to restrict who can bring up a dialog to add a new
          keyguard widget
          @hide -->
     <permission android:name="android.permission.BIND_KEYGUARD_APPWIDGET"
-        android:permissionGroup="android.permission-group.PERSONAL_INFO"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Internal permission allowing an application to query/set which
          applications can bind AppWidgets.
          @hide -->
     <permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature|system" />
 
     <!-- Allows applications to change the background data setting.
     <p>Not for use by third-party applications.
          @hide pending API council -->
     <permission android:name="android.permission.CHANGE_BACKGROUND_DATA_SETTING"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
-        android:description="@string/permdesc_changeBackgroundDataSetting"
-        android:label="@string/permlab_changeBackgroundDataSetting" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi This permission can be used on content providers to allow the global
          search system to access their data.  Typically it used when the
@@ -2692,7 +2132,6 @@
          it is used by applications to protect themselves from everyone else
          besides global search. -->
     <permission android:name="android.permission.GLOBAL_SEARCH"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature|system" />
 
     <!-- Internal permission protecting access to the global search
@@ -2703,39 +2142,32 @@
          ranking).
          @hide -->
     <permission android:name="android.permission.GLOBAL_SEARCH_CONTROL"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Internal permission to allows an application to read indexable data.
         @hide -->
     <permission android:name="android.permission.READ_SEARCH_INDEXABLES"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows applications to set a live wallpaper.
          @hide XXX Change to signature once the picker is moved to its
          own apk as Ghod Intended. -->
     <permission android:name="android.permission.SET_WALLPAPER_COMPONENT"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows applications to read dream settings and dream state.
          @hide -->
     <permission android:name="android.permission.READ_DREAM_STATE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows applications to write dream settings, and start or stop dreaming.
          @hide -->
     <permission android:name="android.permission.WRITE_DREAM_STATE"
-        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allow an application to read and write the cache partition.
          @hide -->
     <permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM"
-        android:label="@string/permlab_cache_filesystem"
-        android:description="@string/permdesc_cache_filesystem"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by default container service so that only
@@ -2744,8 +2176,6 @@
          accessible to the system.
          @hide -->
     <permission android:name="android.permission.COPY_PROTECTED_DATA"
-        android:label="@string/permlab_copyProtectedData"
-        android:description="@string/permlab_copyProtectedData"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Internal permission protecting access to the encryption methods
@@ -2757,23 +2187,17 @@
     <!-- @SystemApi Allows an application to read historical network usage for
          specific networks and applications. @hide -->
     <permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
-        android:label="@string/permlab_readNetworkUsageHistory"
-        android:description="@string/permdesc_readNetworkUsageHistory"
         android:protectionLevel="signature|system" />
 
     <!-- Allows an application to manage network policies (such as warning and disable
          limits) and to define application-specific rules. @hide -->
     <permission android:name="android.permission.MANAGE_NETWORK_POLICY"
-        android:label="@string/permlab_manageNetworkPolicy"
-        android:description="@string/permdesc_manageNetworkPolicy"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to account its network traffic against other UIDs. Used
          by system services like download manager and media server. Not for use by
          third party apps. @hide -->
     <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
-        android:label="@string/permlab_modifyNetworkAccounting"
-        android:description="@string/permdesc_modifyNetworkAccounting"
         android:protectionLevel="signature|system" />
 
     <!-- C2DM permission.
@@ -2787,8 +2211,6 @@
          trust it to verify packages.
     -->
     <permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT"
-        android:label="@string/permlab_packageVerificationAgent"
-        android:description="@string/permdesc_packageVerificationAgent"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by package verifier receiver, to ensure that only the
@@ -2796,16 +2218,12 @@
          @hide
     -->
     <permission android:name="android.permission.BIND_PACKAGE_VERIFIER"
-        android:label="@string/permlab_bindPackageVerifier"
-        android:description="@string/permdesc_bindPackageVerifier"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi @hide Intent filter verifier needs to have this permission before the
          PackageManager will trust it to verify intent filters.
     -->
     <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
-        android:label="@string/permlab_intentFilterVerificationAgent"
-        android:description="@string/permdesc_intentFilterVerificationAgent"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by intent filter verifier receiver, to ensure that only the
@@ -2813,15 +2231,11 @@
          @hide
     -->
     <permission android:name="android.permission.BIND_INTENT_FILTER_VERIFIER"
-        android:label="@string/permlab_bindIntentFilterVerifier"
-        android:description="@string/permdesc_bindIntentFilterVerifier"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to access serial ports via the SerialManager.
          @hide -->
     <permission android:name="android.permission.SERIAL_PORT"
-        android:label="@string/permlab_serialPort"
-        android:description="@string/permdesc_serialPort"
         android:protectionLevel="signature|system" />
 
     <!-- Allows the holder to access content providers from outside an ApplicationThread.
@@ -2831,96 +2245,66 @@
          @hide
     -->
     <permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
-        android:label="@string/permlab_accessContentProvidersExternally"
-        android:description="@string/permdesc_accessContentProvidersExternally"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to hold an UpdateLock, recommending that a headless
          OTA reboot *not* occur while the lock is held.
          @hide -->
     <permission android:name="android.permission.UPDATE_LOCK"
-        android:label="@string/permlab_updateLock"
-        android:description="@string/permdesc_updateLock"
         android:protectionLevel="signatureOrSystem" />
 
     <!-- @SystemApi Allows an application to read the current set of notifications, including
          any metadata and intents attached.
          @hide -->
     <permission android:name="android.permission.ACCESS_NOTIFICATIONS"
-        android:label="@string/permlab_accessNotifications"
-        android:description="@string/permdesc_accessNotifications"
         android:protectionLevel="signature|system" />
 
     <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_access_keyguard_secure_storage"
-        android:description="@string/permdesc_access_keyguard_secure_storage" />
+        android:protectionLevel="signature" />
 
     <!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
     <permission android:name="android.permission.MANAGE_FINGERPRINT"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_manageFingerprint"
-        android:description="@string/permdesc_manageFingerprint" />
-
-    <!-- Allows an app to use fingerprint hardware. -->
-    <permission android:name="android.permission.USE_FINGERPRINT"
-        android:protectionLevel="dangerous"
-        android:label="@string/permlab_useFingerprint"
-        android:description="@string/permdesc_useFingerprint" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to control keyguard.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.CONTROL_KEYGUARD"
-        android:protectionLevel="signature"
-        android:label="@string/permlab_control_keyguard"
-        android:description="@string/permdesc_control_keyguard" />
+        android:protectionLevel="signature" />
 
     <!-- Allows an application to listen to trust changes.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.TRUST_LISTENER"
-                android:protectionLevel="signature"
-                android:label="@string/permlab_trust_listener"
-                android:description="@string/permdesc_trust_listener" />
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to provide a trust agent.
          @hide For security reasons, this is a platform-only permission. -->
     <permission android:name="android.permission.PROVIDE_TRUST_AGENT"
-                android:protectionLevel="signatureOrSystem"
-                android:label="@string/permlab_provide_trust_agent"
-                android:description="@string/permdesc_provide_trust_agent" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Allows an application to launch the trust agent settings activity.
         @hide -->
     <permission android:name="android.permission.LAUNCH_TRUST_AGENT_SETTINGS"
-        android:protectionLevel="signatureOrSystem"
-        android:label="@string/permlab_launch_trust_agent_settings"
-        android:description="@string/permdesc_launch_trust_agent_settings" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- @SystemApi Must be required by an {@link
         android.service.trust.TrustAgentService},
         to ensure that only the system can bind to it.
         @hide -->
     <permission android:name="android.permission.BIND_TRUST_AGENT"
-                android:protectionLevel="signature"
-                android:label="@string/permlab_bind_trust_agent_service"
-                android:description="@string/permdesc_bind_trust_agent_service" />
+        android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link
          android.service.notification.NotificationListenerService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
-        android:label="@string/permlab_bindNotificationListenerService"
-        android:description="@string/permdesc_bindNotificationListenerService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link
          android.service.chooser.ChooserTargetService}, to ensure that
          only the system can bind to it. -->
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
-        android:label="@string/permlab_bindChooserTargetService"
-        android:description="@string/permdesc_bindChooserTargetService"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Must be required by a {@link
@@ -2928,73 +2312,68 @@
          to ensure that only the system can bind to it.
          @hide -->
     <permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
-        android:label="@string/permlab_bindConditionProviderService"
-        android:description="@string/permdesc_bindConditionProviderService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.media.routing.MediaRouteService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_MEDIA_ROUTE_SERVICE"
-        android:label="@string/permlab_bindMediaRouteService"
-        android:description="@string/permdesc_bindMediaRouteService"
         android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.service.dreams.DreamService},
          to ensure that only the system can bind to it. -->
     <permission android:name="android.permission.BIND_DREAM_SERVICE"
-        android:label="@string/permlab_bindDreamService"
-        android:description="@string/permdesc_bindDreamService"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
          carrier setup application to enforce that this permission is required
          @hide This is not a third-party API (intended for OEMs and system apps). -->
     <permission android:name="android.permission.INVOKE_CARRIER_SETUP"
-        android:label="@string/permlab_invokeCarrierSetup"
-        android:description="@string/permdesc_invokeCarrierSetup"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to listen for network condition observations.
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"
-        android:label="@string/permlab_accessNetworkConditions"
-        android:description="@string/permdesc_accessNetworkConditions"
         android:protectionLevel="signature|system" />
 
     <!-- @SystemApi Allows an application to provision and access DRM certificates
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.ACCESS_DRM_CERTIFICATES"
-        android:label="@string/permlab_accessDrmCertificates"
-        android:description="@string/permdesc_accessDrmCertificates"
         android:protectionLevel="signature|system" />
 
     <!-- Api Allows an application to manage media projection sessions.
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"
-        android:label="@string/permlab_manageMediaProjection"
-        android:description="@string/permdesc_manageMediaProjection"
         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to read install sessions
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.READ_INSTALL_SESSIONS"
         android:label="@string/permlab_readInstallSessions"
-        android:description="@string/permdesc_readInstallSessions" />
+        android:description="@string/permdesc_readInstallSessions"
+        android:protectionLevel="normal"/>
 
     <!-- @SystemApi Allows an application to remove DRM certificates
          @hide This is not a third-party API (intended for system apps). -->
     <permission android:name="android.permission.REMOVE_DRM_CERTIFICATES"
-        android:label="@string/permlab_removeDrmCertificates"
-        android:description="@string/permdesc_removeDrmCertificates"
         android:protectionLevel="signature|system" />
 
     <!-- Must be required by a {@link android.service.carrier.CarrierMessagingService}.
          Any service that filters for this intent must be a carrier privileged app. -->
     <permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"
-        android:label="@string/permlab_bindCarrierMessagingService"
-        android:description="@string/permdesc_bindCarrierMessagingService"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows an application to interact with the currently active
+         {@link android.service.voice.VoiceInteractionService}.
+         @hide -->
+    <permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE"
+        android:protectionLevel="signature" />
+
+    <!-- Allows an app that has this permission and a permissions to install packages
+         to request all runtime permissions to be granted at installation.
+     @hide -->
+    <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
+        android:protectionLevel="signature" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml b/core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml
new file mode 100644
index 0000000..7be32af
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_checked_box_inner_merged_animation.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueTo="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueTo="M -7.0,-7.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="133"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml b/core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml
new file mode 100644
index 0000000..fcba2c8
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_checked_check_path_merged_animation.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="166"
+        android:propertyName="pathData"
+        android:valueFrom="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -5.0,-5.00001525879 -5.0,-5.00001525879 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 3.58590698242,3.58601379395 3.58590698242,3.58601379395 c 0.0,0.0 7.58590698242,-7.58601379395 7.58590698242,-7.58601379395 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -9.0,9.00001525879 -9.0,9.00001525879 Z"
+        android:valueTo="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 0.0,1.42500305176 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+        android:valueType="pathType"
+        android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="133"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml b/core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml
new file mode 100644
index 0000000..312003f
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_checked_icon_null_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="scaleX"
+            android:valueFrom="0.2"
+            android:valueTo="0.18"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="scaleX"
+            android:valueFrom="0.18"
+            android:valueTo="0.2"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="scaleY"
+            android:valueFrom="0.2"
+            android:valueTo="0.18"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="scaleY"
+            android:valueFrom="0.18"
+            android:valueTo="0.2"
+            android:interpolator="@interpolator/ic_checkbox_checked_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml b/core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml
new file mode 100644
index 0000000..b5ad5e9d
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_unchecked_box_inner_merged_animation.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="166"
+        android:propertyName="pathData"
+        android:valueFrom="M -7.0,-7.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+        android:valueTo="M 0.0,-0.05 l 0.0,0.0 c 0.02761423749,0.0 0.05,0.02238576251 0.05,0.05 l 0.0,0.0 c 0.0,0.02761423749 -0.02238576251,0.05 -0.05,0.05 l 0.0,0.0 c -0.02761423749,0.0 -0.05,-0.02238576251 -0.05,-0.05 l 0.0,0.0 c 0.0,-0.02761423749 0.02238576251,-0.05 0.05,-0.05 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+        android:valueType="pathType"
+        android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="fillAlpha"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml b/core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml
new file mode 100644
index 0000000..066971a
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_unchecked_box_outer_merged_animation.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+            android:valueTo="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="pathData"
+            android:valueFrom="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+            android:valueTo="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -5.0,-5.00001525879 -5.0,-5.00001525879 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 3.58590698242,3.58601379395 3.58590698242,3.58601379395 c 0.0,0.0 7.58590698242,-7.58601379395 7.58590698242,-7.58601379395 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -9.0,9.00001525879 -9.0,9.00001525879 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="fillAlpha"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml b/core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml
new file mode 100644
index 0000000..fc40d47
--- /dev/null
+++ b/core/res/res/anim/ic_checkbox_unchecked_icon_null_animation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="0.2"
+            android:valueTo="0.18"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="scaleX"
+            android:valueFrom="0.18"
+            android:valueTo="0.2"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="0.2"
+            android:valueTo="0.18"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="scaleY"
+            android:valueFrom="0.18"
+            android:valueTo="0.2"
+            android:interpolator="@interpolator/ic_checkbox_unchecked_animation_interpolator_1" />
+    </set>
+</set>
diff --git a/core/res/res/color/ratingbar_background_material.xml b/core/res/res/color/ratingbar_background_material.xml
new file mode 100644
index 0000000..e6f7488
--- /dev/null
+++ b/core/res/res/color/ratingbar_background_material.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_pressed="true"
+        android:color="?attr/colorControlActivated"
+        android:alpha="?attr/disabledAlpha" />
+    <item
+        android:color="?attr/colorControlNormal"
+        android:alpha="?attr/disabledAlpha" />
+</selector>
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index 3cb4073..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 8fd1480..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index d35b579..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 543c6bc..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index 4fc3c40..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index c184535..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index 9f9dd43..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index 8c629ce..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 81134b5..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index baa5860..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index d7e28366..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 6f24795..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index 22f997d..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index 85f4471..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index ad483c9..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index f24c2fb..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 7a9e9bd..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index af04902..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index 32a6e94..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index c1b4b37..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 34d3ade..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 3d5db53..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index ea35437..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index 48744f8..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index f654517..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 16f959a..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index 98c754b..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index 5827dc2..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 9850d74..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 03ab06b..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 11cdd88..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 874edbf..0000000
--- a/core/res/res/drawable-hdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_star_black_16dp.png b/core/res/res/drawable-hdpi/ic_star_black_16dp.png
new file mode 100644
index 0000000..a728afe
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_star_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_star_black_36dp.png b/core/res/res/drawable-hdpi/ic_star_black_36dp.png
new file mode 100644
index 0000000..4f67f97
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_star_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_star_black_48dp.png b/core/res/res/drawable-hdpi/ic_star_black_48dp.png
new file mode 100644
index 0000000..54d30659
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_star_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_star_half_black_16dp.png b/core/res/res/drawable-hdpi/ic_star_half_black_16dp.png
new file mode 100644
index 0000000..89919a32
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_star_half_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_star_half_black_36dp.png b/core/res/res/drawable-hdpi/ic_star_half_black_36dp.png
new file mode 100644
index 0000000..d28afab
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_star_half_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_star_half_black_48dp.png b/core/res/res/drawable-hdpi/ic_star_half_black_48dp.png
new file mode 100644
index 0000000..befe521
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_star_half_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/list_divider_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/list_divider_mtrl_alpha.9.png
deleted file mode 100644
index 2fa6d7e..0000000
--- a/core/res/res/drawable-hdpi/list_divider_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index 9759818..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 4eb2c4f..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index e6d6b42..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 03cb23a..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index bfe3c3d..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 65bdf42..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index 44f9614b..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index cf8ec38..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 4d624b3..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index 7c4eb7f..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index e90dd31..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 831c0e8..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index 7355dfd..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index be71a69..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index a4a185b..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 8d0386f..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 70793c4..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 632082b..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index e7fc5fb..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index 91a0a33..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 3bd90d6..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 5ac39ec..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 4181983..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index c8b04df..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index b7b3a9f..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 62bc4ed..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index ac463ad..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index 12b605d..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 63a3c6a..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 17660c4..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 7d9de3d..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 8aa1be2..0000000
--- a/core/res/res/drawable-mdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_star_black_16dp.png b/core/res/res/drawable-mdpi/ic_star_black_16dp.png
new file mode 100644
index 0000000..3f5d25e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_star_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_star_black_36dp.png b/core/res/res/drawable-mdpi/ic_star_black_36dp.png
new file mode 100644
index 0000000..92a0f58
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_star_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_star_black_48dp.png b/core/res/res/drawable-mdpi/ic_star_black_48dp.png
new file mode 100644
index 0000000..c636ce8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_star_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_star_half_black_16dp.png b/core/res/res/drawable-mdpi/ic_star_half_black_16dp.png
new file mode 100644
index 0000000..beea92a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_star_half_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_star_half_black_36dp.png b/core/res/res/drawable-mdpi/ic_star_half_black_36dp.png
new file mode 100644
index 0000000..5caae60
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_star_half_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_star_half_black_48dp.png b/core/res/res/drawable-mdpi/ic_star_half_black_48dp.png
new file mode 100644
index 0000000..d53afa22
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_star_half_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/list_divider_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/list_divider_mtrl_alpha.9.png
deleted file mode 100644
index 070bdbf..0000000
--- a/core/res/res/drawable-mdpi/list_divider_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index 2347643..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 70aaa01..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index 01e498a..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 71d1cf7..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index d1e7b1d..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 7db7d06..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index dadb62e..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index f87f744..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index be99d87..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index f83bc05..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index 870071d..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 3a18414..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index f3d1187..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index 4078cca..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index d4849b5..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 6e2af72..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 9244174..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 8c7fe95..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index 71eb1d0..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index 613f38a..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 2d20ccc..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 407f78d..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 1bf24b0..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index a450bd0..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index 63ba593..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 6d05e5a..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index 1c8cd8f..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index b8bc564..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 3d80128..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index c21dfba..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 2dfe90d..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 5f40d73..0000000
--- a/core/res/res/drawable-xhdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_star_black_16dp.png b/core/res/res/drawable-xhdpi/ic_star_black_16dp.png
new file mode 100644
index 0000000..732c48ef
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_star_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_star_black_36dp.png b/core/res/res/drawable-xhdpi/ic_star_black_36dp.png
new file mode 100644
index 0000000..54d30659
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_star_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_star_black_48dp.png b/core/res/res/drawable-xhdpi/ic_star_black_48dp.png
new file mode 100644
index 0000000..7be2280
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_star_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_star_half_black_16dp.png b/core/res/res/drawable-xhdpi/ic_star_half_black_16dp.png
new file mode 100644
index 0000000..5d6f3c8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_star_half_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_star_half_black_36dp.png b/core/res/res/drawable-xhdpi/ic_star_half_black_36dp.png
new file mode 100644
index 0000000..2ed3a20
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_star_half_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_star_half_black_48dp.png b/core/res/res/drawable-xhdpi/ic_star_half_black_48dp.png
new file mode 100644
index 0000000..348d4d8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_star_half_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/list_divider_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/list_divider_mtrl_alpha.9.png
deleted file mode 100644
index 0d2836d..0000000
--- a/core/res/res/drawable-xhdpi/list_divider_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index b754381..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index 517d7a7..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index 2c1d5b6..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 0c6ff7e..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index 0796601..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 9b4e0f8..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index 25767eb..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index cd0951f..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 9ae8165..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index efd9bc6..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index fccbc9d..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index dddafca..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index 7e37433..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index 9bc22de..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index 507ed10..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 6a21c7f..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 0d544d9..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 39da0ac..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index d5ada12..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index d4e096c..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index 468a9b4..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index ea3cd2e..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 0652cb0..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index 768d2b0..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index 1d06a90..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index 8a70a80..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index bf9ec7f..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index cff07b9..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 40f997e..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 6ba84ec..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 766610e..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index 810a029..0000000
--- a/core/res/res/drawable-xxhdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_star_black_16dp.png b/core/res/res/drawable-xxhdpi/ic_star_black_16dp.png
new file mode 100644
index 0000000..c636ce8
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_star_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_star_black_36dp.png b/core/res/res/drawable-xxhdpi/ic_star_black_36dp.png
new file mode 100644
index 0000000..52d03f1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_star_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_star_black_48dp.png b/core/res/res/drawable-xxhdpi/ic_star_black_48dp.png
new file mode 100644
index 0000000..918a395
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_star_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_star_half_black_16dp.png b/core/res/res/drawable-xxhdpi/ic_star_half_black_16dp.png
new file mode 100644
index 0000000..9b268d1
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_star_half_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_star_half_black_36dp.png b/core/res/res/drawable-xxhdpi/ic_star_half_black_36dp.png
new file mode 100644
index 0000000..167d8ae
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_star_half_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_star_half_black_48dp.png b/core/res/res/drawable-xxhdpi/ic_star_half_black_48dp.png
new file mode 100644
index 0000000..64e76bb
--- /dev/null
+++ b/core/res/res/drawable-xxhdpi/ic_star_half_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/list_divider_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/list_divider_mtrl_alpha.9.png
deleted file mode 100644
index b8ac46d..0000000
--- a/core/res/res/drawable-xxhdpi/list_divider_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png
deleted file mode 100644
index f0ff1a7..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png
deleted file mode 100644
index b382df3..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png
deleted file mode 100644
index 8cb4ce2..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png
deleted file mode 100644
index 4db2b01..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png
deleted file mode 100644
index 8c4709b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png
deleted file mode 100644
index 1ad960a..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png
deleted file mode 100644
index e47cc20..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png
deleted file mode 100644
index c4d0d51..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png
deleted file mode 100644
index 915d56a..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png
deleted file mode 100644
index 85795cb..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png
deleted file mode 100644
index 157fd91..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png
deleted file mode 100644
index 9d446de..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png
deleted file mode 100644
index dfac1f0..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png
deleted file mode 100644
index aed6c08..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png
deleted file mode 100644
index 1b8bd6b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png
deleted file mode 100644
index 5dd0e5b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_off_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png
deleted file mode 100644
index 5dd0e5b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_000.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png
deleted file mode 100644
index 1a31ad9..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_001.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png
deleted file mode 100644
index 63c7f12..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_002.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png
deleted file mode 100644
index 847dd08..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_003.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png
deleted file mode 100644
index b93f3cc..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_004.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png
deleted file mode 100644
index 1e3dea7..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_005.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png
deleted file mode 100644
index 5a85238..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_006.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png
deleted file mode 100644
index 35960ca..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_007.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png
deleted file mode 100644
index 6db5555..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_008.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png
deleted file mode 100644
index a9c5851..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_009.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png
deleted file mode 100644
index 38465bd..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_010.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png
deleted file mode 100644
index 15942dc..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_011.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png
deleted file mode 100644
index 67d0d64..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_012.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png
deleted file mode 100644
index 69b5c1b..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_013.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png
deleted file mode 100644
index 0e5d331..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_014.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png b/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png
deleted file mode 100644
index f0ff1a7..0000000
--- a/core/res/res/drawable-xxxhdpi/btn_check_to_on_mtrl_015.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_star_black_16dp.png b/core/res/res/drawable-xxxhdpi/ic_star_black_16dp.png
new file mode 100644
index 0000000..1fa274d
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_star_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_star_black_36dp.png b/core/res/res/drawable-xxxhdpi/ic_star_black_36dp.png
new file mode 100644
index 0000000..918a395
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_star_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_star_black_48dp.png b/core/res/res/drawable-xxxhdpi/ic_star_black_48dp.png
new file mode 100644
index 0000000..67e25d5
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_star_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_star_half_black_16dp.png b/core/res/res/drawable-xxxhdpi/ic_star_half_black_16dp.png
new file mode 100644
index 0000000..266c167
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_star_half_black_16dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_star_half_black_36dp.png b/core/res/res/drawable-xxxhdpi/ic_star_half_black_36dp.png
new file mode 100644
index 0000000..debdb77
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_star_half_black_36dp.png
Binary files differ
diff --git a/core/res/res/drawable-xxxhdpi/ic_star_half_black_48dp.png b/core/res/res/drawable-xxxhdpi/ic_star_half_black_48dp.png
new file mode 100644
index 0000000..bfb6e61
--- /dev/null
+++ b/core/res/res/drawable-xxxhdpi/ic_star_half_black_48dp.png
Binary files differ
diff --git a/core/res/res/drawable/btn_check_material_anim.xml b/core/res/res/drawable/btn_check_material_anim.xml
index 24df879..41caa4e 100644
--- a/core/res/res/drawable/btn_check_material_anim.xml
+++ b/core/res/res/drawable/btn_check_material_anim.xml
@@ -15,159 +15,15 @@
 -->
 
 <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_to_on_mtrl_015"
-                android:tint="?attr/colorControlNormal"
-                android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_enabled="false">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
-                android:tint="?attr/colorControlNormal"
-                android:alpha="?attr/disabledAlpha" />
-    </item>
-    <item android:state_checked="true" android:id="@+id/on">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_015"
-                android:tint="?attr/colorControlActivated" />
-    </item>
-    <item android:id="@+id/off">
-        <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
-                android:tint="?attr/colorControlNormal" />
-    </item>
-    <transition android:fromId="@+id/off" android:toId="@+id/on">
-        <animation-list>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_000"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_001"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_002"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_003"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_004"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_005"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_006"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_007"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_008"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_009"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_010"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_011"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_012"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_013"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_014"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_on_mtrl_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_mtrl_000"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_001"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_002"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_003"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_004"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_005"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_006"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_007"
-                        android:tint="?attr/colorControlActivated" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_008"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_009"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_010"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_011"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_012"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_013"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_014"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-            <item android:duration="15">
-                <bitmap android:src="@drawable/btn_check_to_off_mtrl_015"
-                        android:tint="?attr/colorControlNormal" />
-            </item>
-        </animation-list>
-    </transition>
+    <item android:state_checked="true" android:id="@+id/on"
+        android:drawable="@drawable/ic_checkbox_checked" />
+    <item android:id="@+id/off"
+        android:drawable="@drawable/ic_checkbox_unchecked" />
+
+    <transition android:fromId="@+id/off" android:toId="@+id/on"
+        android:drawable="@drawable/ic_checkbox_unchecked_animation" />
+
+    <transition android:fromId="@+id/on" android:toId="@+id/off"
+        android:drawable="@drawable/ic_checkbox_checked_animation" />
 </animated-selector>
 
diff --git a/core/res/res/drawable/fastscroll_label_left_material.xml b/core/res/res/drawable/fastscroll_label_left_material.xml
index 430d1b0..c825f73 100644
--- a/core/res/res/drawable/fastscroll_label_left_material.xml
+++ b/core/res/res/drawable/fastscroll_label_left_material.xml
@@ -14,14 +14,18 @@
      limitations under the License.
 -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <corners
-        android:topLeftRadius="44dp"
-        android:topRightRadius="44dp"
-        android:bottomRightRadius="44dp" />
-    <padding
-        android:paddingLeft="22dp"
-        android:paddingRight="22dp" />
-    <solid android:color="?attr/colorControlActivated" />
-</shape>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:insetLeft="16dp">
+    <shape
+        android:shape="rectangle"
+        android:tint="?attr/colorControlActivated">
+        <corners
+            android:topLeftRadius="44dp"
+            android:topRightRadius="44dp"
+            android:bottomRightRadius="44dp" />
+        <padding
+            android:left="22dp"
+            android:right="22dp" />
+        <solid android:color="@color/white" />
+    </shape>
+</inset>
diff --git a/core/res/res/drawable/fastscroll_label_right_material.xml b/core/res/res/drawable/fastscroll_label_right_material.xml
index 6e61397..94f5fde 100644
--- a/core/res/res/drawable/fastscroll_label_right_material.xml
+++ b/core/res/res/drawable/fastscroll_label_right_material.xml
@@ -14,14 +14,18 @@
      limitations under the License.
 -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <corners
-        android:topLeftRadius="44dp"
-        android:topRightRadius="44dp"
-        android:bottomLeftRadius="44dp" />
-    <padding
-        android:paddingLeft="22dp"
-        android:paddingRight="22dp" />
-    <solid android:color="?attr/colorControlActivated" />
-</shape>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+       android:insetRight="16dp">
+    <shape
+        android:shape="rectangle"
+        android:tint="?attr/colorControlActivated">
+        <corners
+            android:topLeftRadius="44dp"
+            android:topRightRadius="44dp"
+            android:bottomLeftRadius="44dp" />
+        <padding
+            android:left="22dp"
+            android:right="22dp" />
+        <solid android:color="@color/white" />
+    </shape>
+</inset>
diff --git a/core/res/res/drawable/ic_check_circle_24px.xml b/core/res/res/drawable/ic_check_circle_24px.xml
new file mode 100644
index 0000000..066a8a7
--- /dev/null
+++ b/core/res/res/drawable/ic_check_circle_24px.xml
@@ -0,0 +1,27 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M0 0h24v24H0z"
+        android:fillColor="#00000000"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.0,2.0C6.48,2.0 2.0,6.48 2.0,12.0s4.48,10.0 10.0,10.0 10.0,-4.48 10.0,-10.0S17.52,2.0 12.0,2.0zm-2.0,15.0l-5.0,-5.0 1.41,-1.41L10.0,14.17l7.59,-7.59L19.0,8.0l-9.0,9.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_checkbox_checked.xml b/core/res/res/drawable/ic_checkbox_checked.xml
new file mode 100644
index 0000000..4764115
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_checked.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="ic_checkbox_checked"
+    android:width="32dp"
+    android:viewportWidth="48"
+    android:height="32dp"
+    android:viewportHeight="48"
+    android:tint="?attr/colorControlNormal" >
+    <group
+        android:name="icon_null"
+        android:translateX="24"
+        android:translateY="24"
+        android:scaleX="0.2"
+        android:scaleY="0.2" >
+        <group
+            android:name="check"
+            android:scaleX="7.5"
+            android:scaleY="7.5" >
+            <path
+                android:name="check_path_merged"
+                android:pathData="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -5.0,-5.00001525879 -5.0,-5.00001525879 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 3.58590698242,3.58601379395 3.58590698242,3.58601379395 c 0.0,0.0 7.58590698242,-7.58601379395 7.58590698242,-7.58601379395 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -9.0,9.00001525879 -9.0,9.00001525879 Z"
+                android:fillColor="#FF000000" />
+        </group>
+        <group
+            android:name="box_dilate"
+            android:scaleX="7.5"
+            android:scaleY="7.5" >
+            <path
+                android:name="box_inner_merged"
+                android:pathData="M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+                android:fillColor="#FF000000"
+                android:fillAlpha="0" />
+        </group>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_checkbox_checked_animation.xml b/core/res/res/drawable/ic_checkbox_checked_animation.xml
new file mode 100644
index 0000000..af5eeee
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_checked_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_checkbox_checked" >
+    <target
+        android:name="icon_null"
+        android:animation="@anim/ic_checkbox_checked_icon_null_animation" />
+    <target
+        android:name="check_path_merged"
+        android:animation="@anim/ic_checkbox_checked_check_path_merged_animation" />
+    <target
+        android:name="box_inner_merged"
+        android:animation="@anim/ic_checkbox_checked_box_inner_merged_animation" />
+</animated-vector>
diff --git a/core/res/res/drawable/ic_checkbox_unchecked.xml b/core/res/res/drawable/ic_checkbox_unchecked.xml
new file mode 100644
index 0000000..410f0bc
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_unchecked.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="ic_checkbox_unchecked"
+    android:width="32dp"
+    android:viewportWidth="48"
+    android:height="32dp"
+    android:viewportHeight="48"
+    android:tint="?attr/colorControlNormal" >
+    <group
+        android:name="icon_null"
+        android:translateX="24"
+        android:translateY="24"
+        android:scaleX="0.2"
+        android:scaleY="0.2" >
+        <group
+            android:name="check"
+            android:scaleX="7.5"
+            android:scaleY="7.5" >
+            <path
+                android:name="box_outer_merged"
+                android:pathData="M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M -2.0,5.00001525879 c 0.0,0.0 -1.4234161377,-1.40159606934 -1.4234161377,-1.40159606934 c 0.0,0.0 1.41409301758,-1.41409301758 1.41409301758,-1.41409301758 c 0.0,0.0 0.00932312011719,-0.0124053955078 0.00932312011719,-0.0124053955078 c 0.0,0.0 0.0234069824219,-0.0235137939453 0.0234069824219,-0.0235137939453 c 0.0,0.0 1.41409301758,1.41409301758 1.41409301758,1.41409301758 c 0.0,0.0 -1.4375,1.43751525879 -1.4375,1.43751525879 Z"
+                android:fillColor="#FF000000"
+                android:fillAlpha="0" />
+        </group>
+        <group
+            android:name="box_dilate"
+            android:scaleX="7.5"
+            android:scaleY="7.5" >
+            <path
+                android:name="box_inner_merged"
+                android:pathData="M -7.0,-7.0 l 14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -14.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-14.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+                android:fillColor="#FF000000" />
+        </group>
+    </group>
+</vector>
diff --git a/core/res/res/drawable/ic_checkbox_unchecked_animation.xml b/core/res/res/drawable/ic_checkbox_unchecked_animation.xml
new file mode 100644
index 0000000..605fce1
--- /dev/null
+++ b/core/res/res/drawable/ic_checkbox_unchecked_animation.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_checkbox_unchecked" >
+    <target
+        android:name="icon_null"
+        android:animation="@anim/ic_checkbox_unchecked_icon_null_animation" />
+    <target
+        android:name="box_outer_merged"
+        android:animation="@anim/ic_checkbox_unchecked_box_outer_merged_animation" />
+    <target
+        android:name="box_inner_merged"
+        android:animation="@anim/ic_checkbox_unchecked_box_inner_merged_animation" />
+</animated-vector>
diff --git a/core/res/res/drawable/list_divider_material.xml b/core/res/res/drawable/list_divider_material.xml
index babb646..658a59d 100644
--- a/core/res/res/drawable/list_divider_material.xml
+++ b/core/res/res/drawable/list_divider_material.xml
@@ -14,7 +14,10 @@
      limitations under the License.
 -->
 
-<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/list_divider_mtrl_alpha"
-    android:tint="?attr/colorForeground"
-    android:alpha="0.12" />
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:tint="?attr/colorForeground">
+    <solid android:color="#1f000000" />
+    <size
+        android:height="1dp"
+        android:width="1dp" />
+</shape>
diff --git a/core/res/res/drawable/ratingbar_full_empty_material.xml b/core/res/res/drawable/ratingbar_full_empty_material.xml
index a2ae7d9..12b01ba 100644
--- a/core/res/res/drawable/ratingbar_full_empty_material.xml
+++ b/core/res/res/drawable/ratingbar_full_empty_material.xml
@@ -16,11 +16,14 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
-        <bitmap android:src="@drawable/btn_rating_star_off_mtrl_alpha"
-            android:tint="?attr/colorControlActivated" />
+        <bitmap
+            android:src="@drawable/btn_rating_star_off_mtrl_alpha"
+            android:tint="?attr/colorControlActivated"
+            android:alpha="?attr/disabledAlpha"/>
     </item>
     <item>
-        <bitmap android:src="@drawable/btn_rating_star_off_mtrl_alpha"
+        <bitmap
+            android:src="@drawable/btn_rating_star_off_mtrl_alpha"
             android:tint="?attr/colorControlNormal" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/ratingbar_full_filled_material.xml b/core/res/res/drawable/ratingbar_full_filled_material.xml
index 801c85f..f167dae7 100644
--- a/core/res/res/drawable/ratingbar_full_filled_material.xml
+++ b/core/res/res/drawable/ratingbar_full_filled_material.xml
@@ -16,11 +16,13 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true">
-        <bitmap android:src="@drawable/btn_rating_star_on_mtrl_alpha"
+        <bitmap
+            android:src="@drawable/btn_rating_star_on_mtrl_alpha"
             android:tint="?attr/colorControlActivated" />
     </item>
     <item>
-        <bitmap android:src="@drawable/btn_rating_star_on_mtrl_alpha"
+        <bitmap
+            android:src="@drawable/btn_rating_star_on_mtrl_alpha"
             android:tint="?attr/colorControlNormal" />
     </item>
 </selector>
diff --git a/core/res/res/drawable/ratingbar_full_material.xml b/core/res/res/drawable/ratingbar_full_half_material.xml
similarity index 60%
copy from core/res/res/drawable/ratingbar_full_material.xml
copy to core/res/res/drawable/ratingbar_full_half_material.xml
index 122dd1d..8b78b43 100644
--- a/core/res/res/drawable/ratingbar_full_material.xml
+++ b/core/res/res/drawable/ratingbar_full_half_material.xml
@@ -14,11 +14,15 @@
      limitations under the License.
 -->
 
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@id/background"
-        android:drawable="@drawable/ratingbar_full_empty_material" />
-    <item android:id="@id/secondaryProgress"
-        android:drawable="@drawable/ratingbar_full_empty_material" />
-    <item android:id="@id/progress" 
-        android:drawable="@drawable/ratingbar_full_filled_material" />
-</layer-list>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true">
+        <bitmap
+            android:src="@drawable/btn_rating_star_off_mtrl_alpha"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item>
+        <bitmap
+            android:src="@drawable/btn_rating_star_off_mtrl_alpha"
+            android:tint="?attr/colorControlNormal" />
+    </item>
+</selector>
diff --git a/core/res/res/drawable/ratingbar_indicator_material.xml b/core/res/res/drawable/ratingbar_indicator_material.xml
new file mode 100644
index 0000000..d8c6ee1
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_indicator_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/background">
+        <bitmap
+            android:src="@drawable/ic_star_black_36dp"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:id="@+id/secondaryProgress">
+        <bitmap
+            android:src="@drawable/ic_star_half_black_36dp"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/progress">
+        <bitmap
+            android:src="@drawable/ic_star_black_36dp"
+            android:tint="?attr/colorControlActivated"
+            android:tileModeX="repeat" />
+    </item>
+</layer-list>
diff --git a/core/res/res/drawable/ratingbar_material.xml b/core/res/res/drawable/ratingbar_material.xml
new file mode 100644
index 0000000..0cd7fac
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_material.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/background">
+        <bitmap
+            android:src="@drawable/ic_star_black_48dp"
+            android:tint="@color/ratingbar_background_material" />
+    </item>
+    <item android:id="@+id/secondaryProgress">
+        <bitmap
+            android:src="@drawable/ic_star_half_black_48dp"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/progress">
+        <bitmap
+            android:src="@drawable/ic_star_black_48dp"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+</layer-list>
diff --git a/core/res/res/drawable/ratingbar_small_material.xml b/core/res/res/drawable/ratingbar_small_material.xml
new file mode 100644
index 0000000..f24241c
--- /dev/null
+++ b/core/res/res/drawable/ratingbar_small_material.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:id="@+id/background">
+        <bitmap
+            android:src="@drawable/ic_star_black_16dp"
+            android:tint="?attr/colorControlNormal"
+            android:alpha="?attr/disabledAlpha" />
+    </item>
+    <item android:id="@+id/secondaryProgress">
+        <bitmap
+            android:src="@drawable/ic_star_half_black_16dp"
+            android:tint="?attr/colorControlActivated" />
+    </item>
+    <item android:id="@+id/progress">
+        <bitmap
+            android:src="@drawable/ic_star_black_16dp"
+            android:tint="?attr/colorControlActivated"
+            android:tileModeX="repeat" />
+    </item>
+</layer-list>
diff --git a/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_0.xml b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_0.xml
new file mode 100644
index 0000000..ceac663
--- /dev/null
+++ b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_0.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 l 1.0,0.0 l 0.0,1.0" />
diff --git a/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_1.xml b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_1.xml
new file mode 100644
index 0000000..26bc8ad
--- /dev/null
+++ b/core/res/res/interpolator/ic_checkbox_checked_animation_interpolator_1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.0,1.0 1.0,1.0" />
diff --git a/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml
new file mode 100644
index 0000000..ceac663
--- /dev/null
+++ b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_0.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 l 1.0,0.0 l 0.0,1.0" />
diff --git a/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml
new file mode 100644
index 0000000..26bc8ad
--- /dev/null
+++ b/core/res/res/interpolator/ic_checkbox_unchecked_animation_interpolator_1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.0,1.0 1.0,1.0" />
diff --git a/core/res/res/layout/floating_popup_close_overflow_button.xml b/core/res/res/layout/floating_popup_close_overflow_button.xml
new file mode 100644
index 0000000..a1d2811
--- /dev/null
+++ b/core/res/res/layout/floating_popup_close_overflow_button.xml
@@ -0,0 +1,24 @@
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:layout_height="match_parent"
+    android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
+    android:minHeight="@dimen/floating_toolbar_height"
+    android:src="?android:attr/actionModeCloseDrawable"
+    android:contentDescription="@string/floating_toolbar_close_overflow_description"
+    android:background="?attr/selectableItemBackgroundBorderless" />
diff --git a/core/res/res/layout/floating_popup_open_overflow_button.xml b/core/res/res/layout/floating_popup_open_overflow_button.xml
index 4c1176c..dca5384 100644
--- a/core/res/res/layout/floating_popup_open_overflow_button.xml
+++ b/core/res/res/layout/floating_popup_open_overflow_button.xml
@@ -21,5 +21,5 @@
     android:minWidth="@dimen/floating_toolbar_menu_button_minimum_width"
     android:minHeight="@dimen/floating_toolbar_height"
     android:src="@drawable/ic_menu_moreoverflow_material"
-    android:contentDescription="@string/action_menu_overflow_description"
+    android:contentDescription="@string/floating_toolbar_open_overflow_description"
     android:background="?attr/selectableItemBackgroundBorderless" />
diff --git a/core/res/res/layout/floating_popup_overflow_list_item b/core/res/res/layout/floating_popup_overflow_list_item
new file mode 100644
index 0000000..9294f3b
--- /dev/null
+++ b/core/res/res/layout/floating_popup_overflow_list_item
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textAppearance="?android:attr/textAppearanceListItemSmall"
+    android:gravity="center_vertical"
+    android:minWidth="@dimen/floating_toolbar_menu_button_side_padding"
+    android:minHeight="@dimen/floating_toolbar_height"
+    android:paddingLeft="@dimen/floating_toolbar_menu_button_side_padding"
+    android:paddingRight="@dimen/floating_toolbar_menu_button_side_padding"
+    android:paddingTop="0dp"
+    android:paddingBottom="0dp"
+    android:singleLine="true"
+    android:ellipsize="end"
+    android:fontFamily="sans-serif"
+    android:textSize="@dimen/floating_toolbar_text_size"
+    android:textAllCaps="true" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 44db8cc..825ed5a 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Swerfbanier af"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Soek vir diens"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-oproepe"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nie aangestuur nie"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> sekondes"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"deaktiveer LED wat oordrag aandui wanneer kamera gebruik word"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Laat \'n pre-geïnstalleerde stelselprogram toe om die LED wat kamera-gebruik aandui, te deaktiveer."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Laat \'n voorafgeïnstalleerde stelselprogram toe om stelselgebeure aan die kameradiens te stuur."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deaktiveer tablet permanent"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"deaktiveer TV permanent"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"deaktiveer foon permanent"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"begin CDMA-TV-opstelling regstreeks"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"begin dadelik met CDMA-foonopstelling"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Laat die program toe om CDMA-voorsiening te begin. Kwaadwillige programme kan dalk onnodig CDMA-voorsiening begin."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"bestuur kennisgewings vir liggingopdatering"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Laat die jeug program toe om liggingopdatering-berigte van die radio te aktiveer/deaktiveer. Nie vir gebruik deur normale programme nie."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"kry toegang tot insleutel-eienskappe"</string>
@@ -757,7 +772,7 @@
   </string-array>
     <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"Kon nie verwerk nie. Probeer weer."</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"Hardeware is nie beskikbaar nie."</string>
-    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie geberg word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
+    <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Vingerafdruk kan nie gestoor word nie. Verwyder asseblief \'n bestaande vingerafdruk."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
     <string name="fingerprint_error_vendor" msgid="3175724710791609491">"Vingerafdrukuittelling is bereik. Probeer weer."</string>
   <string-array name="fingerprint_error_vendor">
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Laat \'n program toe om DRM-sertifikate te verwyder. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind aan \'n diensverskaffer-boodskapdiens"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dit laat die houer toe om aan die top-koppelvlak van \'n diensverskaffer-boodskapdiens te bind. Behoort nooit vir gewone programme nodig te wees nie."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"beleef wisselwerking met steminteraksiediens"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Laat die houer toe om met die huidige aktiewe steminteraksiediens wisselwerking te hê. Behoort nooit vir gewone programme nodig te wees nie."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Stel wagwoordreëls"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Beheer die lengte en die karakters wat in skermslotwagwoorde en -PIN\'e toegelaat word."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor pogings om skerm te ontsluit"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Laat die program toe om te verifieer dat \'n pakket installeerbaar is."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind aan \'n pakkieverifieerder"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifieer voornemefilter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Laat die program toe om te kyk of \'n voornemefilter geverifieer is of nie."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind aan \'n voornemefilterverifieerder"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Laat die houer toe om versoeke te rig aan voornemefilterverifieerders. Behoort nooit vir normale programme nodig te wees nie."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"verkry toegang tot inhoud ekstern"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Verminder dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Vermeerder jaar"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Verminder jaar"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Vorige maand"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Volgende maand"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselleer"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Vee uit"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Kies minute"</string>
     <string name="select_day" msgid="7774759604701773332">"Kies maand en dag"</string>
     <string name="select_year" msgid="7952052866994196170">"Kies jaar"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> gekies"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> uitgevee"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Om hierdie skerm te ontspeld, raak en hou tegelyk Terug en Oorsig."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vra PIN voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vra ontsluitpatroon voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vra wagwoord voordat jy ontspeld"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Om batterylewe te help verbeter, verminder batterybespaarder jou toestel se werkverrigting en beperk vibrasie, liggingdienste en die meeste agtergronddata. E-pos, boodskappe en ander programme wat op sinkronisering staatmaak, sal dalk nie opdateer tensy jy hulle oopmaak nie.\n\nBatterybespaarder skakel outomaties af wanneer jou toestel besig is om te laai."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Totdat jou ontspantyd om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> eindig"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Tot jou aftyd verby is"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index be3a864..e0966ec 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"የዝውውር ሰንደቅ ጠፍቷል"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"አገልግሎት ፍለጋ"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"የWi-Fi ጥሪ ማድረጊያ"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ጠፍቷል"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi ተመርጧል"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"የተንቀሳቃሽ ስልክ ተመርጧል"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi ብቻ"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>፡አልተላለፈም"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>፡<xliff:g id="DIALING_NUMBER">{1}</xliff:g> ከ<xliff:g id="TIME_DELAY">{2}</xliff:g> ሰከንዶች በኋላ"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ካሜራው ስራ ላይ ሲሆን የማስተላለፍ አመልካች ኤል ኢ ዲን ያሰናክሉ"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ቀድሞ የተጫነ የስርዓት መተግበሪያ ካሜራውን አመላካች ኤል ኢ ዲ እንዳይጠቀም እንዲያሰናክል ያስችለዋል።"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Allows a pre-installed system application to send the camera service system"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"በቋሚነት ጡባዊ አቦዝን"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ቴሌቪዥን እስከመጨረሻ አሰናክል"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"በቋሚነት ስልኩን አቦዝን"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"በቀጥታ የሲዲኤምኤ ቴሌቪዥን ማዋቀር ጀምር"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"የCDMA ስልክ ጫን በቀጥታ አስጀምር"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"መተግበሪያው የCDMA ዝግጅት ለመጀመር ይፈቅዳሉ ። ተንኮል አዘል መተግበሪያዎች አላስፈላጊ የCDMA ዝግጅት ይጀምራሉ።"</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"ሲም ካርድ ማዘጋጀትን ጀምር"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"መተግበሪያው የሲም ገቢር ማድረግ ጥያቄዎችን እንዲይዝ ያስችለዋል። መተግበሪያው በቀጥታ ገቢር ማድረግን ሊያከናውን ይችላል ወይም ይህን ተግባር ለሌላ መተግበሪያ ሊያስተላልፍ ይችላል።"</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"የሥፍራ አዘምን ማሳወቂያዎችን ተቆጣጠር"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ከሬድዮ የአከባቢ አዘምን ማሳወቂያዎችን ለማንቃት/ለማስወገድ ለመተግበሪያው ይፈቅዳል፡፡ ለመደበኛ መተግበሪያዎች ጥቅም አይደለም፡፡"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"የድረስባህሪያት ምልከታ"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"አንድ መተግበሪያ የDRM እውቅና ማረጋገጫዎችን እንዲያስወግድ ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ወደሞባይል አገልግሎት ሰጪ የመልዕክት አገልግሎት አያይዝ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ያዢው በሞባይል አገልግሎት ሰጪ የመልዕክት አላላክ አገልግሎት ላይ ከፍተኛውን ደረጃ በይነ ገጽ እንዲይዝ ይፈቅድለታል። ለመደበኛ መተግበሪያ በጭራሽ አያስፈልግም።"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ከድምጽ መስተጋብራዊ አገልግሎት ጋር መስተጋብር ይፍጠሩ"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"ያዡን አሁን ካለው ንቁ የድምጽ መስተጋብራዊ አገልግሎት ጋር መስተጋብር እንዲፈጽም ይፈቅድለታል። ለመደበኛ መተግበሪያዎች በጭራሽ ማስፈለግ የለበትም።"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"የይለፍ ቃል ደንቦች አዘጋጅ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"በማያ ገጽ መቆለፊያ የይለፍ ቃሎች እና ፒኖች ውስጥ የሚፈቀዱ ቁምፊዎችን እና ርዝመታቸውን ተቆጣጠር።"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"የማሳያ-ክፈት ሙከራዎችን አሳይ"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ፓኬጅ መጫን የሚችል መሆኑን ለማረጋገጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"በፓኬጅ አረጋጋጭ የተወሰነ"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"የፍላጎት ማጣሪያን አረጋግጥ"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"የፍላጎት ማጣሪያው የተረጋገጠ ወይም ያልተረጋገጠ መሆኑን ለመፈተሽ እንዲችል መተግበሪያውን ይፈቅድለታል።"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"በፍላጎት ማጣሪያ አረጋገጭ ተገደብ"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"የፍላጎት ማጣሪያ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ መተግበሪያዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ይዘት አቅራቢዎችን በውጭ በኩል ድረስባቸው"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ቀን ቀንስ"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ዓመት ጨምር"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ዓመት ቀንስ"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ያለፈው ወር"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"ቀጣይ ወር"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ይቅር"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ሰርዝ"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"ደቂቃዎችን ይምረጡ"</string>
     <string name="select_day" msgid="7774759604701773332">"ወር እና ቀን ይምረጡ"</string>
     <string name="select_year" msgid="7952052866994196170">"ዓመት ይምረጡ"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ተመርጧል"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ተሰርዟል"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ይህን ማያ ገጽ ለመንቀል ተመለስን እና አጠቃላይ እይታን በተመሳሳይ ይንኳቸውና ይያዟቸው።"</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ከመንቀል በፊት ፒን ጠይቅ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ከመንቀል በፊት የማስከፈቻ ስርዓተ-ጥለት ጠይቅ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"የባትሪ ዕድሜን ለማሻሻል ማገዝ እንዲቻል፣ ኢሜይል፣ መልዕክት አላላክ እና ሌሎች በማመሳሰል ላይ የሚመረኮዙ መተግበሪያዎች እርስዎ ካልከፈቱዋቸው በቀር አይዘምኑም።\n\nየባትሪ ኃይል ቆጣቢ የእርስዎ መሣሪያ ኃይል በሚሞላበት ጊዜ በራስ-ሰር ይጠፋል።"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"የጥገና ጊዜዎ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> ላይ እስኪያበቃ ድረስ"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"የእርስዎ የማይገኙበት ጊዜ እስከሚያበቃ ድረስ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a451930..7c256fb 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -128,9 +128,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"إعلان بانر للتجوال متوقف"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"البحث عن خدمة"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"‏الاتصال عبر Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"إيقاف"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏شبكة Wi-Fi مُفضّلة"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"شبكة الجوّال مُفضّلة"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"‏Wi-Fi فقط"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: لم تتم إعادة التوجيه"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> بعد <xliff:g id="TIME_DELAY">{2}</xliff:g> ثانية"</string>
@@ -589,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"‏تعطيل مؤشر LED للإرسال عندما تكون الكاميرا قيد الاستخدام"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"‏للسماح لتطبيق نظام مثبت مسبقًا لتعطيل مؤشر LED لاستخدام الكاميرا."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"للسماح لتطبيق نظام مثبت مسبقًا بإرسال أحداث نظام خدمة الكاميرا."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"تعطيل الجهاز اللوحي نهائيًا"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"تعطيل التلفزيون نهائيًا"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"تعطيل الهاتف على الدوام"</string>
@@ -637,6 +644,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"‏تشغيل إعداد تلفزيون CDMA مباشرة"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"‏بدء إعداد هاتف CDMA مباشرة"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"‏للسماح للتطبيق ببدء توفير CDMA. قد تبدأ التطبيقات الضارة توفير CDMA بدون الحاجة إلى ذلك."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"‏بدء إعداد شريحة SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"‏للسماح للتطبيق بمعالجة طلبات تنشيط SIM. ويمكن أن يجري التطبيق التنشيط مباشرةً أو يمكن أن يرسل تفويضًا إلى تطبيق آخر."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"التحكم في اشعارات تحديث الموقع"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"للسماح للتطبيق بتمكين/تعطيل إشعارات تحديث الموقع من اللاسلكي. ليس للاستخدام بواسطة التطبيقات العادية."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"الدخول إلى خصائص الإيداع"</string>
@@ -843,6 +852,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"‏للسماح لأحد التطبيقات بإزالة شهادات DRM. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"الالتزام بخدمة المراسلة التابعة لمشغل شبكة الجوّال"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"يسمح لحامله بالالتزام بواجهة المستوى العالي لخدمة المراسلة التابعة لمشغل شبكة الجوَّال. ومن المفترض عدم الحاجة إليه مع التطبيقات العادية."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"التفاعل مع خدمة التفاعل الصوتي"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"للسماح للمالك بالتفاعل مع خدمة التفاعل الصوتي النشطة حاليًا. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تعيين قواعد كلمة المرور"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"للتحكم في الطول والأحرف المسموح بها في كلمات المرور وأرقام التعريف الشخصي في قفل الشاشة."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"مراقبة محاولات إلغاء قفل الشاشة"</string>
@@ -1140,6 +1151,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"السماح للتطبيق بالتحقق من إمكانية تثبيت حزمة."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"الالتزام بمحقق حزمة"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"التحقق من فلتر الأهداف"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"للسماح للتطبيق بفحص ما إذا كان فلتر الأهداف قد تم التحقق منه أم لا."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"الالتزام بمحقق فلتر الأهداف"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"للسماح للمالك بإجراء طلبات محققي فلتر الأهداف. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"الدخول إلى مزودي المحتوى خارجيًا"</string>
@@ -1593,6 +1608,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"تقليل الأيام"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"زيادة الأعوام"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"تقليل الأعوام"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"الشهر السابق"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"الشهر التالي"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"إلغاء"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف"</string>
@@ -1849,7 +1866,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"تحديد الدقائق"</string>
     <string name="select_day" msgid="7774759604701773332">"تحديد الشهر واليوم"</string>
     <string name="select_year" msgid="7952052866994196170">"تحديد العام"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"تم تحديد <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"تم حذف <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> المخصص للعمل"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"لإلغاء تثبيت هذه الشاشة، يمكنك لمس \"رجوع\" و\"نظرة عامة\" في آن واحد مع الاستمرار."</string>
@@ -1860,6 +1876,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"المطالبة برقم التعريف الشخصي قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"المطالبة بنقش إلغاء القفل قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"المطالبة بكلمة المرور قبل إزالة التثبيت"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"للمساعدة في تحسين عمر البطارية، يساعد موفر البطارية في تقليل أداء الجهاز ويفرض قيدًا على الاهتزاز وخدمات الموقع ومعظم بيانات الخلفية. قد لا يتم تحديث البريد الإلكتروني والمراسلة والتطبيقات الأخرى التي تعتمد على المزامنة ما لم تفتحها.\n\nيتم إيقاف موفر البطارية تلقائيًا أثناء شحن الجهاز."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"إلى أن ينتهي وقت التوقف عن العمل في <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"حتى انتهاء وقت التعطل"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index fa5b464..15f19d0 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Банерът за роуминг е изключен"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Търси се покритие"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Обаждания през Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Не е пренасочено"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> след <xliff:g id="TIME_DELAY">{2}</xliff:g> секунди"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"деактивиране на светодиодния индикатор за предаване, когато камерата се използва"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Разрешава на предварително инсталирано системно приложение да деактивира светодиодния индикатор за използване на камерата."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Разрешава на предварително инсталирано системно приложение да изпраща известия за системни събития до услугата за камера."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"деактивиране на таблета за постоянно"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"деактивиране на телевизора за постоянно"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"деактивиране на телефона за постоянно"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"директно стартиране на настройването на телевизора със CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"директно стартиране на настройката на телефона през CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Разрешава на приложението да стартира обезпечаване за CDMA. Злонамерените приложения могат ненужно да стартират този процес."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"контролиране на известията за актуализиране на местоположението"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Разрешава на приложението да активира или деактивира известията за актуализиране на местоположението от радиомодула. Не е предназначено за нормални приложения."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"достъп до свойствата на услугата за проверка"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Разрешава на приложението да премахва сертификатите за управление на цифровите права (DRM). Нормалните приложения би трябвало никога да се нуждаят от това."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"свързване с услуга за съобщения от оператор"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Разрешава на притежателя да се свърже към интерфейса от най-високото ниво на услуга за съобщения от оператор. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"взаимодействане с услугата за гласово взаимодействие"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Разрешава на притежателя да взаимодейства с понастоящем активната услуга за гласово взаимодействие. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Задаване на правила за паролата"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролира дължината и разрешените знаци за паролите и ПИН кодовете за заключване на екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Наблюдаване на опитите за отключване на екрана"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Разрешава на приложението да провери дали пакетът може да се инсталира."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обвързване с верификатор на пакета"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"проверка на филтъра за намерения"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Разрешава на приложението да проверява дали даден филтър за намерения е потвърден или не."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"свързв. с вериф. на филтри за намерения"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Разрешава на притежателя да отправя заявки за верификатори на филтрите за намерения. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"външен достъп до доставчиците на съдърж."</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Намаляване на дните"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Увеличаване на годините"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Намаляване на годините"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Предишен месец"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Следващ месец"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отказ"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Изтриване"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Избиране на минути"</string>
     <string name="select_day" msgid="7774759604701773332">"Избиране на месец и ден"</string>
     <string name="select_year" msgid="7952052866994196170">"Избиране на година"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Избрахте <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Изтрихте <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> за работа"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"За да освободите екрана, докоснете и задръжте едновременно бутона за връщане назад и този за общ преглед."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитване за ПИН код преди освобождаване"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запитване за фигура за отключване преди освобождаване"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запитване за парола преди освобождаване"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"С цел удължаване на живота на батерията режимът за запазването й намалява ефективността на устройството ви и ограничава вибрирането, услугите за местоположение и повечето данни на заден план. Приложенията за електронна поща, съобщения и др., които разчитат на синхронизиране, може да не се актуализират, освен ако не ги отворите.\n\nРежимът за запазване на батерията се изключва автоматично, когато устройството ви се зарежда."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"До приключване на неактивността в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До приключването на почивката ви"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index b29768d..6b8845b 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"রোমিং ব্যানার বন্ধ আছে"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"পরিষেবা অনুসন্ধান করা হচ্ছে"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi কলিং"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"বন্ধ আছে"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"পছন্দের Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"পছন্দের মোবাইল নেটওয়ার্ক"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"শুধুমাত্র Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ফরওয়ার্ড করা হয়নি"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> সেকেন্ড পরে"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"যখন ক্যামেরা ব্যবহারে থাকে তখন ট্রান্সমিট সূচক LED অক্ষম করে"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"আগে থেকে ইনস্টল থাকা একটি সিস্টেম অ্যাপ্লিকেশানকে ক্যামেরা ব্যবহারের সূচক LEDটিকে অক্ষম করার অনুমতি দেয়৷"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"ক্যামেরা পরিষেবার সিস্টেম ইভেন্টগুলি পাঠাতে আগে থেকে ইনস্টল থাকা একটি সিস্টেম অ্যাপ্লিকেশানকে অনুমতি দেয়৷"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ট্যাবলেটকে স্থায়ীভাবে অক্ষম করে"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"টিভি স্থায়ীভাবে অক্ষম করে"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ফোনকে স্থায়ীভাবে অক্ষম করে"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"সরাসরি CDMA TV সেটআপ শুরু করে"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA ফোন সেটআপ সরাসরি শুরু করে"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"অ্যাপ্লিকেশানকে CDMA প্রস্তুতি শুরু করার অনুমতি দেয়৷ ক্ষতিকারক অ্যাপ্লিকেশান অকারণে CDMA প্রস্তুতি শুরু করতে পারে৷"</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM কার্ডের সেটআপ শুরু করুন"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"অ্যাপ্লিকেশানটিকে SIM সক্রিয়করণের অনুরোধ পরিচালনা করতে অনুমতি দিন। অ্যাপ্লিকেশানটি সরাসরি সক্রিয়করণের কার্য সম্পাদনা করতে বা অন্য অ্যাপ্লিকেশানে প্রতিনিধি নিযুক্ত করতে পারে।"</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"অবস্থান আপডেট বিজ্ঞপ্তিগুলিকে নিয়ন্ত্রণ করে"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"অ্যাপ্লিকেশানকে রেডিও থেকে অবস্থানের আপডেটের বিজ্ঞপ্তি সক্ষম/অক্ষম করতে দেয়৷ সাধারণ অ্যাপ্লিকেশানগুলির ব্যবহারের জন্য নয়৷"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"চেক ইন বৈশিষ্ট্যাবলী অ্যাক্সেস করে"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"কোনো অ্যাপ্লিকেশানকে DRM শংসাপত্রগুলি সরানোর অনুমতি দেয়। সাধারণ অ্যাপ্লিকেশানগুলির জন্য কখনো প্রয়োজন হয় না।"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"একটি ক্যারিয়ার বার্তাপ্রেরণ পরিষেবা আবদ্ধ করতে"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ধারককে, একটি ক্যারিয়ার বার্তাপ্রেরণ পরিষেবার উচ্চ স্তরের ইন্টারফেসে জুড়তে অনুমতি দেয়৷ সধারণ অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হয় না৷"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ভয়েস আলাপচারিতা পরিষেবার সাথে ইন্টারঅ্যাক্ট করুন"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"বর্তমানে সক্ষম ভয়েস আলাপচারিতা পরিষেবার সাথে ইন্টারঅ্যাক্ট করার জন্য হোল্ডারকে অনুমতি দিন৷ স্বাভাবিক অ্যাপ্লিকেশানগুলির জন্য কখনই প্রয়োজন হবে না।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"পাসওয়ার্ড নিয়মগুলি সেট করে"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"স্ক্রীন লক করার পাসওয়ার্ডগুলিতে অনুমতিপ্রাপ্ত অক্ষর এবং দৈর্ঘ্য নিয়ন্ত্রণ করে৷"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"স্ক্রীণ আনলক করার প্রচেষ্টাগুলি নিরীক্ষণ করে"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"অ্যাপ্লিকেশানকে ইনস্টলযোগ্য প্যাকেজ যাচাই করার অনুমতি দেয়৷"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"একটি প্যাকেজ যাচাইকারীতে সংলগ্ন করে"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ধারককে, প্যাকেজ যাচাইকারীতে অনুরোধগুলি পাঠাতে দেয়৷ সাধারণ অ্যাপ্লিকেশানগুলির জন্য কখনোই প্রয়োজনীয় নয়৷"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"অভিপ্রায় ফিল্টার যাচাই করুন"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"কোনো অভিপ্রায় ফিল্টার যাচাই করা হয়েছে কি না অ্যাপ্লিকেশানটিকে তা পরীক্ষা করার মঞ্জুরি দেয়৷"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"একটি অভিপ্রায় ফিল্টার যাচাইকারী আবদ্ধ করুন"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ধারককে,অভিপ্রায় ফিল্টার যাচাইকারীতে অনুরোধগুলি পাঠাতে দেয়৷ সাধারণ অ্যাপ্লিকেশানগুলির জন্য কখনোই প্রয়োজনীয় নয়৷"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"সিরিয়াল পোর্টগুলি অ্যাক্সেস করে"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"সিরিয়াল ম্যানেজার API ব্যবহার করে ধারককে সিরিয়াল পোর্টগুলি অ্যাক্সেস করতে অনুমতি দেয়৷"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"বাহ্যিকভাবে সামগ্রীর পরিষেবা প্রদানকারীদের অ্যাক্সেস করুন"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"দিন কম করুন"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"বছর বাড়ান"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"বছর কম করুন"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"পূর্ববর্তী মাস"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"পরের মাস"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"বাতিল করুন"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"মুছুন"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"মিনিট নির্বাচন করুন"</string>
     <string name="select_day" msgid="7774759604701773332">"মাস এবং দিন নির্বাচন করুন"</string>
     <string name="select_year" msgid="7952052866994196170">"বছর নির্বাচন করুন"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> নির্বাচন করা হয়েছে"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> মুছে ফেলা হয়েছে"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"কর্মক্ষেত্র <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"এই স্ক্রীনটিকে আনপিন করতে, \'ফিরুন\' এবং \'এক নজরে\' একসাথে স্পর্শ করুন এবং ধরে রাখুন৷"</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"আনপিন করার আগে PIN চান"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"আনপিন করার আগে আনলক প্যাটার্ন চান"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"আনপিন করার আগে পাসওয়ার্ড চান"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ব্যাটরির লাইফ উন্নত করতে সহায়তা করতে, ব্যাটারি সাশ্রয়কারী আপনার ডিভাইসের কার্যসম্পাদনা হ্রাস করে এবং কম্পন, অবস্থান পরিষেবাসমূহ এবং অধিকাংশ ব্যাকগ্রাউন্ড ডেটা সীমিত করে৷ ইমেল, বার্তাপ্রেরণ এবং অন্যান্য অ্যাপ্লিকেশানগুলিকে যেগুলি সিঙ্কের উপর নির্ভর করে সেগুলিকে আপনি না খোলা পর্যন্ত নাও আপডেট হতে পারে৷\n\nআপনার ডিভাইসটিকে যখন চার্জ করা হয় তখন ব্যাটারি সাশ্রয়কারী স্বয়ংক্রিয়ভাবে বন্ধ হয়ে যায়৷"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>টার সময়ে আপনার ডাউনটাইম শেষ হওয়া পর্যন্ত"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"আপনার ডাউনটাইম শেষ না হওয়া পর্যন্ত"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 6a0066a..02ca2ac 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Bàner d\'itinerància desactivat"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"S\'està cercant el servei"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Trucades per Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no s\'ha desviat"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> després de <xliff:g id="TIME_DELAY">{2}</xliff:g> segons"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desactiva la transmissió del LED indicador en fer servir la càmera"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet que una aplicació dels sistema preinstal·lada desactivi el LED indicador d\'ús de la càmera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permet que una aplicació dels sistema preinstal·lada enviï esdeveniments del sistema al servei de la càmera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactiva la tauleta de manera permanent"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"desactivar el televisor de manera permanent"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar definitivament el telèfon"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"iniciar directament la configuració del televisor CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directament la configuració del telèfon CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permet que l\'aplicació iniciï l\'aprovisionament CDMA. Les aplicacions malicioses poden iniciar l\'aprovisionament CDMA innecessàriament."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar les notificacions d\'actualització de la ubicació"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet que l\'aplicació activi i desactivi les notificacions d\'actualització de la ubicació del senyal mòbil. No la poden fer servir les aplicacions normals."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"accedir a les propietats d\'accés"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permet que una aplicació suprimeixi els certificats DRM. No ha de ser mai necessari per a aplicacions normals."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular-la al servei de missatgeria d\'un operador"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permet que el propietari la pugui vincular a la interfície principal del servei de missatgeria d\'un operador. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interaccionar amb el servei d\'interacció de veu"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permet que el titular interaccioni amb el servei d\'interacció de veu actiu actualment. Mai no hauria de ser necessari per a les aplicacions habituals."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir les normes de contrasenya"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Permet controlar la longitud i el nombre de caràcters permesos a les contrasenyes i als PIN del bloqueig de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Controlar els intents de desbloqueig de pantalla"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet que l\'aplicació verifiqui si un paquet es pot instal·lar."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincula a un verificador de paquets"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar el filtre d\'intenció"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permet que l\'aplicació comprovi si un filtre d\'intenció està verificat."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"enllaçar amb verific. de filtre d\'inten."</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permet que el titular sol·liciti verificadors de filtres. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accedeix als proveïdors de contingut externament"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Fes disminuir el dia"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Fes augmentar l\'any"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Fes disminuir l\'any"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mes següent"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel·la"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Suprimeix"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Selecciona els minuts"</string>
     <string name="select_day" msgid="7774759604701773332">"Selecciona un mes i un dia"</string>
     <string name="select_year" msgid="7952052866994196170">"Selecciona un any"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionat"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> suprimit"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de la feina"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Per anul·lar la fixació d\'aquesta pantalla, mantén premudes les opcions Enrere i Visió general alhora."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demana el codi PIN abans d\'anul·lar la fixació"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sol·licita el patró de desbloqueig per anul·lar la fixació"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demana la contrasenya abans d\'anul·lar la fixació"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Per allargar la durada de la bateria, l\'estalvi de bateria redueix el rendiment del dispositiu i limita l\'ús de la vibració, dels serveis d\'ubicació i de la majoria de les dades en segon pla. És possible que el correu electrònic, la missatgeria i altres aplicacions que depenen de la sincronització no s\'actualitzin fins que els obris.\n\nL\'estalvi de bateria es desactiva de manera automàtica quan el dispositiu es posa a carregar."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Fins que no finalitzi la inactivitat a les <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>."</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Fins que finalitzi el temps d\'inactivitat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7429bfc..17076d5 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -126,9 +126,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner roamingu je vypnutý"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Vyhledávání služby"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Volání přes Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepřesměrováno"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
@@ -587,6 +597,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"vypnutí indikátoru LED přenosu při použití fotoaparátu"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje předinstalované systémové aplikaci vypnout kontrolku LED fotoaparátu."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Umožňuje předinstalované systémové aplikaci odesílat systémové události služby fotoaparátu."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trvalé vypnutí tabletu"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"trvalé vypnutí televize"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"trvalé vypnutí telefonu"</string>
@@ -635,6 +646,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"přímé spuštění nastavení kódového multiplexu v televizi"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"přímo spustit nastavení telefonu CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Umožňuje aplikaci zahájit poskytování CDMA. Škodlivé aplikace mohou poskytování CDMA zahájit samovolně."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ovládání oznámení o aktualizaci polohy"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Umožňuje aplikaci zapnout nebo vypnout oznámení o aktualizaci polohy pomocí bezdrátového modulu. Toto oprávnění není určeno pro běžné aplikace."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"přístup k vlastnostem Checkin"</string>
@@ -841,6 +856,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Povoluje aplikaci odstranit certifikáty DRM. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"navázat se na nejvyšší úroveň rozhraní služby zasílání zpráv prostřednictvím operátora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Umožňuje držiteli navázat se na nejvyšší úroveň rozhraní služby zasílání zpráv prostřednictvím operátora. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"komunikace se službou hlasové interakce"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Umožňuje držiteli komunikovat s právě aktivní službou hlasové interakce. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavit pravidla pro heslo"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ovládání délky a znaků povolených v heslech a kódech PIN zámku obrazovky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovat pokusy o odemčení obrazovky"</string>
@@ -1138,6 +1155,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikaci ověřit, zda balíček lze nainstalovat."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"navázat na ověřovatele balíčků"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ověření filtru objektů intent"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Umožňuje aplikaci zkontrolovat, zda je filtr objektů intent ověřený."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vazba na ověření filtru objektů intent"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Umožňuje držiteli podávat žádosti o ověření filtrů objektů intent. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externí přístup k poskytovatelům obsahu"</string>
@@ -1577,6 +1598,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Ubrat den"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Přidat rok"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Ubrat rok"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Předchozí měsíc"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Příští měsíc"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušit"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Smazat"</string>
@@ -1831,7 +1854,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Zvolte minuty"</string>
     <string name="select_day" msgid="7774759604701773332">"Vyberte měsíc a den"</string>
     <string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Vybrána položka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Číslice <xliff:g id="KEY">%1$s</xliff:g> byla smazána"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Pracovní <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Chcete-li tuto obrazovku uvolnit, klepněte současně na možnosti Zpět a Přehled a podržte je."</string>
@@ -1842,6 +1864,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Před uvolněním požádat o kód PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Před uvolněním požádat o bezpečnostní gesto"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Před uvolněním požádat o heslo"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Spořič baterie za účelem prodloužení výdrže baterie snižuje výkon zařízení a omezuje vibrace, služby určování polohy a většinu dat na pozadí. E-mail, aplikace pro zasílání zpráv a další aplikace, které používají synchronizaci, se nemusejí aktualizovat, dokud je neotevřete.\n\nPři nabíjení zařízení se spořič baterie automaticky vypne."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Dokud v <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> neskončí pozastavení"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Dokud neskončí pozastavení"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index b6014ef..c3c485f 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roamingbanner fra"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Søger efter tjeneste"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Opkald via Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderestillet"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"deaktiver sendelysdioden, når kameraet er i brug"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Tillader, at en forudinstalleret systemapplikation deaktiverer lysdioden for brug af kameraet."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Giver en forudinstalleret systemapp tilladelse til at sende systembegivenheder til kameratjenesten."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deaktiver tabletcomputeren permanent"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"deaktivere tv\'et permanent"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"deaktiver telefonen permanent"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"direkte starte konfiguration af CDMA TV"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"start CDMA-telefonopsætning direkte"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Tillader, at appen kan starte CDMA-levering. Ondsindede apps kan starte unødvendig CDMA-levering."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontroller underretninger om placeringsopdatering"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Tillader, at appen kan aktivere/deaktivere underretninger om placeringsopdatering fra senderen. Anvendes ikke i almindelige apps."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"egenskaber for adgangskontrol"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Tillader, at en app fjerner DRM-certifikater. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"knytte til et mobilselskabs beskedtjeneste"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dette giver indehaveren mulighed for at knytte sig til det øverste grænsefladeniveau for et mobilselskabs beskedtjeneste. Dette bør ikke være nødvendigt i normale apps."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interager med stemmestyringstjenesten"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Giver brugeren tilladelse til at interagere med den i øjeblikket aktive stemmestyringstjeneste. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Indstil regler for adgangskode"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollér længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -925,7 +942,7 @@
     <string name="phoneTypeCar" msgid="8738360689616716982">"Bil"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Virksomhed (hovednummer)"</string>
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
-    <string name="phoneTypeMain" msgid="6766137010628326916">"Hoved"</string>
+    <string name="phoneTypeMain" msgid="6766137010628326916">"Hovednr."</string>
     <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Andre faxbeskeder"</string>
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Telex"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"bekræft intent-filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Tillader, at appen kan kontrollere, om et intent-filter er bekræftet eller ej."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"knyt til en bekræfter af intent-filtre"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af intent-filtre. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"adgang til indholdsleverandører eksternt"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tidligere dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Senere år"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Tidligere år"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Forrige måned"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Næste måned"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuller"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slet"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Vælg minutter"</string>
     <string name="select_day" msgid="7774759604701773332">"Vælg måned og dag"</string>
     <string name="select_year" msgid="7952052866994196170">"Vælg år"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> er valgt"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> – arbejde"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil frigøre dette skærmbillede, skal du trykke på Tilbage og Oversigt på samme tid og holde fingeren nede."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bed om pinkode inden frigørelse"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bed om oplåsningsmønster ved deaktivering"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bed om adgangskode inden frigørelse"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen slukker automatisk, når enheden oplader."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Indtil din nedetid slutter kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Indtil nedetiden ophører"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 0db7fea..aedf0eb 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roaming-Banner aus"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Suche nach Dienst"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"WLAN-Telefonie"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nicht weitergeleitet"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> nach <xliff:g id="TIME_DELAY">{2}</xliff:g> Sekunden."</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"LED-Anzeige für Übertragung bei Kameranutzung deaktivieren"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Vorinstallierte System-Apps können die LED-Anzeige für die Kameranutzung deaktivieren."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Ermöglicht vorinstallierten System-Apps, Systemereignisse an den Kameradienst zu senden"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"Tablet dauerhaft deaktivieren"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"Fernseher dauerhaft deaktivieren"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA-TV-Einrichtung direkt starten"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA-Telefoneinrichtung direkt starten"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ermöglicht der App, die CDMA-Bereitstellung zu starten. Schädliche Apps können so die CDMA-Bereitstellung unnötigerweise starten."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"Benachrichtigungen für Standortaktualisierung steuern"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ermöglicht der App, Mobilfunkbenachrichtigungen über Standort-Updates zu aktivieren bzw. zu deaktivieren. Nicht für normale Apps vorgesehen."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"Auf Check-in-Eigenschaften zugreifen"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Ermöglicht einer App das Entfernen von DRM-Zertifikaten. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"An einen Mobilfunkanbieter-SMS/MMS-Dienst binden"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ermöglicht dem Inhaber die Bindung an die Oberfläche eines Mobilfunkanbieter-SMS/MMS-Dienstes auf oberster Ebene. Für normale Apps sollte dies nie erforderlich sein."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"Mit Sprachinteraktionsdienst interagieren"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Ermöglicht dem Inhaber die Interaktion mit dem gerade aktiven Sprachinteraktionsdienst. Für normale Apps sollte dies nie erforderlich sein."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Zulässige Länge und Zeichen für Passwörter für die Displaysperre festlegen"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ermöglicht der App die Überprüfung, ob ein Paket installiert werden kann"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"An Paketprüfung binden"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"Intent-Filter verifizieren"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Ermöglicht einer App, zu überprüfen, ob ein Intent-Filter verifiziert wurde"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"An Intent-Filter-Verifizierung binden"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Ermöglicht dem Inhaber, Anfragen für die Verifizierung von Intent-Filtern zu senden. Sollte für normale Apps nie benötigt werden."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Extern auf Content-Anbieter zugreifen"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Tag verringern"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Jahr verlängern"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Jahr verringern"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Vormonat"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nächster Monat"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Abbrechen"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Löschen"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Minuten auswählen"</string>
     <string name="select_day" msgid="7774759604701773332">"Monat und Tag auswählen"</string>
     <string name="select_year" msgid="7952052866994196170">"Jahr auswählen"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ausgewählt"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> gelöscht"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (geschäftlich)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Um die Fixierung dieses Bildschirms aufzuheben, berühren und halten Sie gleichzeitig \"Zurück\" und \"Übersicht\"."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vor dem Beenden nach PIN fragen"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vor dem Beenden nach Entsperrungsmuster fragen"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vor dem Beenden nach Passwort fragen"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Der Energiesparmodus schont den Akku, indem er die Leistung des Geräts reduziert und die Vibrationsfunktion sowie die meisten Hintergrunddatenaktivitäten einschränkt. E-Mail, SMS/MMS und andere Apps, die auf Ihrem Gerät synchronisiert werden, werden möglicherweise erst nach dem Öffnen aktualisiert.\n\nDer Energiesparmodus wird automatisch deaktiviert, wenn Ihr Gerät aufgeladen wird."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Bis zum Ende der Downtime um <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Bis zum Ende der Inaktivität"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 8a9e9d3..ef46290 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Διαφημιστικό πλαίσιο περιαγωγής απενεργοποιημένο"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Αναζήτηση υπηρεσιών"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Κλήση Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Δεν προωθήθηκε"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> μετά από <xliff:g id="TIME_DELAY">{2}</xliff:g> δευτερόλεπτα"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"απενεργοποίηση ένδειξης LED μετάδοσης όταν χρησιμοποιείται η φωτογραφική μηχανή"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Επιτρέπει σε μια προεγκατεστημένη εφαρμογή συστήματος να απενεργοποιήσει την ένδειξη LED χρήσης της φωτογραφικής μηχανής."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Επιτρέπει σε μια προεγκατεστημένη εφαρμογή συστήματος να αποστέλλει στην υπηρεσία κάμερας συμβάντα συστήματος."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"μόνιμη απενεργοποίηση του tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"μόνιμη απενεργοποίηση της τηλεόρασης"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"μόνιμη απενεργοποίηση τηλεφώνου"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"άμεση έναρξη της ρύθμισης CDMA της τηλεόρασης"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"άμεση έναρξη της εγκατάστασης τηλεφώνου CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Επιτρέπει στην εφαρμογή να ξεκινήσει την παροχή CDMA. Κακόβουλες εφαρμογές ενδέχεται να ξεκινήσουν την παροχή CDMA χωρίς λόγο"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"έλεγχος ειδοποιήσεων ενημέρωσης τοποθεσίας"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Επιτρέπει στην εφαρμογή την ενεργοποίηση/απενεργοποίηση των ειδοποιήσεων ενημέρωσης τοποθεσίας από το ραδιόφωνο. Δεν προορίζεται για χρήση από συνήθεις εφαρμογές."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"πρόσβαση σε ιδιότητες ελέγχου εισόδου"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Επιτρέπει σε μια εφαρμογή την κατάργηση πιστοποιητικών DRM. Δεν χρειάζεται ποτέ για κανονικές εφαρμογές."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"δέσμευση σε υπηρεσία ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Επιτρέπει στον κάτοχο τη δέσμευση στη διεπαφή ανωτάτου επιπέδου μιας υπηρεσίας ανταλλαγής μηνυμάτων εταιρείας κινητής τηλεφωνίας. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"αλληλεπίδραση με την υπηρεσία φωνητικής αλληλεπίδρασης"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Επιτρέπει στον κάτοχο να αλληλεπιδρά με την τρέχουσα ενεργή υπηρεσία φωνητικής αλληλεπίδρασης. Δεν απαιτείται για τις συνήθεις εφαρμογές."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ορισμός κανόνων κωδικού πρόσβασης"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ελέγξτε την έκταση και τους επιτρεπόμενους χαρακτήρες σε κωδικούς πρόσβασης κλειδώματος οθόνης και PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Παρακολούθηση προσπαθειών ξεκλειδώματος οθόνης"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Επιτρέπει στην εφαρμογή να επαληθεύσει τη δυνατότητα εγκατάστασης ενός πακέτου."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"δέσμευση με επαλήθευση πακέτου"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"επαλήθευση φίλτρου πρόθεσης"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Επιτρέπει στην εφαρμογή να ελέγχει εάν ένα φίλτρο πρόθεσης είναι επαληθευμένο ή όχι."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"σύνδεση σε προγρ.επαλήθ.φίλτρου πρόθεσης"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης φίλτρων πρόθεσης. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"εξωτερική πρόσβαση σε παρόχους περιεχ."</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Μείωση ημέρας"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Αύξηση έτους"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Μείωση έτους"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Προηγούμενος μήνας"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Επόμενος μήνας"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ακύρωση"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Διαγραφή"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Επιλογή λεπτών"</string>
     <string name="select_day" msgid="7774759604701773332">"Επιλογή μήνα και ημέρας"</string>
     <string name="select_year" msgid="7952052866994196170">"Επιλογή έτους"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Επιλέχτηκε το στοιχείο <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> διαγράφηκε"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Εργασία <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Για να ξεκαρφιτσώσετε αυτήν την οθόνη, πατήστε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Να γίνεται ερώτηση για το PIN, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Να γίνεται ερώτηση για το μοτίβο ξεκλειδώματος, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Να γίνεται ερώτηση για τον κωδικό πρόσβασης, πριν από το ξεκαρφίτσωμα"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Προκειμένου να βελτιώσει τη διάρκεια ζωής της μπαταρίας σας, η Εξοικονόμηση μπαταρίας μειώνει την απόδοση της συσκευής σας και περιορίζει λειτουργίες όπως η δόνηση, οι υπηρεσίες τοποθεσίας και τα περισσότερα δεδομένα παρασκηνίου. Το ηλεκτρονικό ταχυδρομείο, η ανταλλαγή μηνυμάτων και άλλες εφαρμογές που βασίζονται στο συγχρονισμό ενδέχεται να μην ενημερώνονται έως ότου τις ανοίξετε.\n\nΗ Εξοικονόμηση μπαταρίας απενεργοποιείται αυτόματα όταν η συσκευή σας φορτίζει."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Έως τη λήξη του νεκρού χρόνου σας στις <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Έως τη λήξη του νεκρού χρόνου σας"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 389b584..539bca1 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roaming Banner Off"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Searching for Service"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi Calling"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Mobile preferred"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi only"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disable transmit indicator LED when camera is in use"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Allows a pre-installed system application to disable the camera use indicator LED."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Allows a pre-installed system application to send the camera service system events."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanently disable tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanently disable TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"permanently disable phone"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"directly start CDMA TV setup"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"directly start CDMA phone setup"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Allows the app to start CDMA provisioning. Malicious apps may unnecessarily start CDMA provisioning."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"start SIM card setup"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Allows the app to handle SIM activation requests. The app may directly perform activation or may delegate to another app."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"control location update notifications"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Allows the app to enable/disable location update notifications from the radio. Not for use by normal apps."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"access check-in properties"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind to a carrier messaging service"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interact with voice interaction service"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Allows the holder to interact with the currently active voice interaction service. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verify intent filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Allows the app to check if an intent filter is verified or not."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind to an intent filter verifier"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Allows the holder to make requests of intent filter verifiers. Should never be needed for normal apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"access content providers externally"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Previous month"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Next month"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
     <string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
     <string name="select_year" msgid="7952052866994196170">"Select year"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Until your downtime ends at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Until your downtime ends"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 389b584..539bca1 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roaming Banner Off"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Searching for Service"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi Calling"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Mobile preferred"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi only"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disable transmit indicator LED when camera is in use"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Allows a pre-installed system application to disable the camera use indicator LED."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Allows a pre-installed system application to send the camera service system events."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanently disable tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanently disable TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"permanently disable phone"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"directly start CDMA TV setup"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"directly start CDMA phone setup"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Allows the app to start CDMA provisioning. Malicious apps may unnecessarily start CDMA provisioning."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"start SIM card setup"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Allows the app to handle SIM activation requests. The app may directly perform activation or may delegate to another app."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"control location update notifications"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Allows the app to enable/disable location update notifications from the radio. Not for use by normal apps."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"access check-in properties"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind to a carrier messaging service"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interact with voice interaction service"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Allows the holder to interact with the currently active voice interaction service. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verify intent filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Allows the app to check if an intent filter is verified or not."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind to an intent filter verifier"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Allows the holder to make requests of intent filter verifiers. Should never be needed for normal apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"access content providers externally"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Previous month"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Next month"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
     <string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
     <string name="select_year" msgid="7952052866994196170">"Select year"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Until your downtime ends at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Until your downtime ends"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 389b584..539bca1 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roaming Banner Off"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Searching for Service"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi Calling"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Off"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferred"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Mobile preferred"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi only"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Not forwarded"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> after <xliff:g id="TIME_DELAY">{2}</xliff:g> seconds"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disable transmit indicator LED when camera is in use"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Allows a pre-installed system application to disable the camera use indicator LED."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Allows a pre-installed system application to send the camera service system events."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanently disable tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanently disable TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"permanently disable phone"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"directly start CDMA TV setup"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"directly start CDMA phone setup"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Allows the app to start CDMA provisioning. Malicious apps may unnecessarily start CDMA provisioning."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"start SIM card setup"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Allows the app to handle SIM activation requests. The app may directly perform activation or may delegate to another app."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"control location update notifications"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Allows the app to enable/disable location update notifications from the radio. Not for use by normal apps."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"access check-in properties"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Allows an application to remove DRM certficates. Should never be needed for normal apps."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind to a carrier messaging service"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interact with voice interaction service"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Allows the holder to interact with the currently active voice interaction service. Should never be needed for normal apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Set password rules"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Control the length and the characters allowed in screen lock passwords and PINs."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitor screen-unlock attempts"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verify intent filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Allows the app to check if an intent filter is verified or not."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bind to an intent filter verifier"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Allows the holder to make requests of intent filter verifiers. Should never be needed for normal apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"access content providers externally"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Decrease day"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Increase year"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Decrease year"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Previous month"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Next month"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancel"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Select minutes"</string>
     <string name="select_day" msgid="7774759604701773332">"Select month and day"</string>
     <string name="select_year" msgid="7952052866994196170">"Select year"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selected"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> deleted"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Work <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"To unpin this screen, touch and hold Back and Overview at the same time."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ask for PIN before unpinning"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ask for password before unpinning"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Until your downtime ends at <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Until your downtime ends"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 642ab92..13473ca 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner de roaming desactivado"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servicio"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Llamada por Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: no se ha remitido"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> después de <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Inhabilitar el indicador LED de transmisión mientras se utiliza la cámara"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que una aplicación del sistema instalada previamente inhabilite el indicador LED de uso de la cámara."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permite que una aplicación del sistema preinstalada envíe eventos del sistema al servicio de cámara."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar tablet de forma permanente"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"inhabilitar la TV permanentemente"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar dispositivo de manera permanente"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"iniciar directamente la configuración de la TV CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del dispositivo"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite que la aplicación inicie el método de acceso CDMA. Las aplicaciones maliciosas pueden iniciar el método CDMA de forma innecesaria."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite que la aplicación habilite/deshabilite notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizar este permiso."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder a las propiedades de protección"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite que una aplicación elimine certificados DRM. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular al servicio de mensajería del proveedor"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite al propietario vincularse a la interfaz de nivel superior del servicio de mensajería del proveedor. Las aplicaciones regulares no lo necesitan."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interactuar con el servicio de interacción por voz"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permite interactuar con el servicio de interacción por voz que se encuentra activo. Las aplicaciones normales no deberían de necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Permite controlar la longitud y los caracteres permitidos en las contraseñas y los PIN para el bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisa los intentos para desbloquear la pantalla"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Vincular a un verificador de paquetes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intento"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que la aplicación compruebe si se verificó un filtro de intento."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vincular a verificador filtro de intento"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite que el titular solicite verificadores de filtros de intentos. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a proveedores externamente"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir día"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mes siguiente"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
     <string name="select_day" msgid="7774759604701773332">"Seleccionar mes y día"</string>
     <string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> borrado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para dejar de fijar esta pantalla, mantén presionados los botones para volver y Recientes al mismo tiempo."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para quitar fijación"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para quitar fijación"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para quitar fijación"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, el ahorro de batería reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayoría de los datos en segundo plano. Es posible que el correo electrónico, la mensajería y otras aplicaciones que se basan en la sincronización no puedan actualizarse, a menos que los abras.\n\nEl ahorro de batería se desactiva de forma automática cuando el dispositivo se está cargando."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hasta que termine el tiempo de inactividad a la(s) <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hasta que finalice el tiempo de inactividad"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8e1c37b..4b53bd4 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner de itinerancia desactivado"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servicio"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Llamadas Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: No desviada"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> transcurridos <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"inhabilitar el indicador LED de transmisión mientras se utiliza la cámara"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que una aplicación de sistema instalada previamente inhabilite el indicador LED que advierte del uso de la cámara."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permite que una aplicación del sistema preinstalada envíe eventos del sistema al servicio de cámara."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inhabilitar tablet de forma permanente"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"inhabilitar permanentemente la TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"inhabilitar el teléfono de forma permanente"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"iniciar directamente la configuración CDMA de la TV"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente el método de acceso CDMA del teléfono"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite que la aplicación inicie el método de acceso CDMA. Las aplicaciones malintencionadas pueden iniciar el método CDMA inútilmente."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de la ubicación"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite que la aplicación habilite o inhabilite las notificaciones de actualización de la señal móvil. Las aplicaciones normales no deben usar este permiso."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder a propiedades de registro"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite a una aplicación eliminar los certificados DRM. Las aplicaciones normales no deberí­an necesitar este permiso."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"enlazar con el servicio de mensajería de un operador"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite enlazar con la interfaz de nivel superior del servicio de mensajería de un operador. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interactuar con el servicio de interacción de voz"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permite al propietario interactuar con el servicio de interacción de voz actualmente activo. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecimiento de reglas de contraseña"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla la longitud y los caracteres permitidos en los PIN y en las contraseñas de bloqueo de pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Control de intentos de bloqueo de pantalla"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"enlazar con un detector de paquetes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intento"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que la aplicación compruebe si un filtro de intento se ha verificado."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"enlazar con detector filtro de intento"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite que se envíen solicitudes de detectores de filtros de intentos. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a proveedores de contenido externamente"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir días"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar año"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir año"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Próximo mes"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
     <string name="select_day" msgid="7774759604701773332">"Seleccionar mes y día"</string>
     <string name="select_year" msgid="7952052866994196170">"Seleccionar año"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabajo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para desactivar esta pantalla, mantén pulsados los botones de retroceso y Visión general al mismo tiempo."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar PIN para desactivar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar patrón de desbloqueo para desactivar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar contraseña para desactivar"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ayudar a mejorar la duración de la batería, la función de ahorro de energía reduce el rendimiento del dispositivo y limita la vibración, los servicios de ubicación y la mayor parte de la transmisión de datos en segundo plano. Es posible que las aplicaciones que se sincronizan, como las de correo y mensajes, no se actualicen a menos que las abras.\n\nLa función de ahorro de energía se desactiva automáticamente cuando el dispositivo se está cargando."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hasta que el tiempo de inactividad finalice el <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hasta que finalice el tiempo de inactividad"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 10f1a45..7221611 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Rändlusbänner väljas"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Teenuse otsimine"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"WiFi-kõned"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: pole suunatud"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundi pärast"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"keela kaamera kasutamisel näidikutule kasutamine"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Lubab eelinstallitud süsteemirakendusel keelata kaamera näidikutule kasutamise."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Lubab eelinstallitud süsteemirakendusel saata kaamerateenuse süsteemi sündmusi."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"blokeeri tahvelarvuti jäädavalt"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"teleri alaline keelamine"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"blokeeri telefon jäädavalt"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA TV seadistamise otsekäivitus"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA-telefoniseadistuse otse käivitamine"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Võimaldab rakendusel käivitada CDMA ettevalmistamise. Pahatahtlikud rakendused võivad CDMA ettevalmistamise asjatult käivitada."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrolli asukoha värskendamise teatisi"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Võimaldab rakendusel lubada/keelata asukoha värskendamise teatised raadiost. Mitte kasutada tavarakenduste puhul."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"juurdepääs registreerimisatribuutidele"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Lubab rakendusel eemaldada DRM-sertifikaate. Pole kunagi vajalik tavaliste rakenduste puhul."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"seose loomine operaatori sõnumisideteenusega"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Lubab omanikul luua seose operaatori sõnumisideteenuse ülataseme liidesega. Pole kunagi vajalik tavalise rakenduse puhul."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"suhtlemine häälsuhtluse teenusega"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Võimaldab omanikul suhelda praegu aktiivse häälsuhtluse teenusega. Seda ei peaks tavapäraste rakenduste puhul kunagi vaja olema."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parooli reeglite määramine"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Juhitakse ekraaniluku paroolide ja PIN-koodide pikkusi ning lubatud tähemärkide seadeid."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekraani avamiskatsed"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Võimaldab rakendusel kinnitada, et paketti saab installida."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sidumine paketi kinnitajaga"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"kavatsuste filtri kinnitamine"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Võimaldab rakendusel kontrollida, kas kavatsuste filter on kinnitatud või mitte."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"sidumine kavatsuste filtri kinnitajaga"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Võimaldab omanikul teha taotlusi kavatsuste filtri kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"väline juurdepääs sisupakkujatele"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Päeva vähendamine"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aasta suurendamine"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Aasta vähendamine"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Eelmine kuu"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Järgmine kuu"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Tühista"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Kustuta"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Minutite valimine"</string>
     <string name="select_day" msgid="7774759604701773332">"Kuu ja päeva valimine"</string>
     <string name="select_year" msgid="7952052866994196170">"Aasta valimine"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> on valitud"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> on kustutatud"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Töö <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ekraanikuva vabastamiseks puudutage pikalt samal ajal nuppe Tagasi ja Ülevaade."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Enne vabastamist küsi PIN-koodi"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Enne vabastamist küsi avamismustrit"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Enne vabastamist küsi parooli"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Aku kestuse parandamiseks vähendab akusäästja teie seadme toimivust ning piirab vibratsiooni, asukohateenuseid ja suuremat osa taustaandmetest. E-posti, sõnumsidet ja muid sünkroonimisele tuginevaid rakendusi võidakse värskendada ainult siis, kui te need avate.\n\nAkusäästja lülitatakse seadme laadimise ajal automaatselt välja."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Kuni seisakuaja lõppemiseni kell <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kuni puhkeaja lõpuni"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index e6ade17..6309ff3 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Ibiltaritzari buruzko jakinarazpena desaktibatuta"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Zerbitzu bila"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi bidezko deiak"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desaktibatuta"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi sarea hobesten da"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Sare mugikorra hobesten da"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi sarea soilik"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ez da desbideratu"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> zenbakira <xliff:g id="TIME_DELAY">{2}</xliff:g> segundotan"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Desgaitu LED argi adierazlea kamera abian denean"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Kamera erabiltzen ari dela adierazten duen LED argia desgaitzeko aukera ematen dio sisteman aurrez instalatutako aplikazio bati."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Kamerara sistemako gertaerak bidaltzeko aukera ematen dio sisteman aurrez instalatutako aplikazio bati."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desgaitu telefonoa behin betiko"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"Desgaitu telebista betiko"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"desgaitu telefonoa behin betiko"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"Hasi zuzenean telebista CDMA bidez konfiguratzen"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"hasi zuzenean CDMA bidezko telefono-konfigurazioa"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMA horniketa hastea baimentzen die aplikazioei. Aplikazio gaiztoek CDMA horniketa has dezakete behar ez denean ere."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"Hasi SIM txartelaren konfigurazioa"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"SIM bidezko aktibazio-eskaerak kontrolatzea baimentzen die aplikazioei. Aplikazioak automatikoki gauza dezake aktibazioa, edo aukera hori beste aplikazio bati eman diezaioke."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"Kontrolatu kokapen-eguneratzeen jakinarazpenak"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Kokapenari buruz irratiak bidalitako informazio eguneratuaren jakinarazpenak gaitzea edo desgaitzea baimentzen die aplikazioei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"atzitu erregistratze-propietateak"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM ziurtagiriak kentzea baimentzen die aplikazioei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"lotu operadorearen mezularitza-zerbitzuari"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Operadore baten mezularitza-zerbitzuaren goi-mailako interfazeari lotzea baimentzen die erabiltzaileei. Aplikazio normalek ez lukete inoiz beharko."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"Jardun elkarrekintzan ahots bidezko elkarrekintza-zerbitzuarekin"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Unean aktibo dagoen ahots bidezko elkarrekintza-zerbitzuarekin elkarrekintzan jardutea baimentzen die titularrei. Aplikazio normalek ez lukete behar."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ezarri pasahitzen arauak"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolatu pantaila blokeoaren pasahitzen eta PINen luzera eta onartutako karaktereak."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Kontrolatu pantaila desblokeatzeko saiakerak"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Paketeak instala daitezkeen egiaztatzea baimentzen die aplikazioei."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"lotu pakete-egiaztatzaile batekin"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pakete-egiaztatzaileei eskaerak egitea baimentzen die aplikazioei. Aplikazio normalek ez lukete beharko."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"Egiaztatu saiakera-iragazkia"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Saiakera-iragazki bat egiaztatuta dagoen ala ez egiaztatzea baimentzen die aplikazioei."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"Lotu saiakera-iragazkien egiaztatzaile bati"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Saiakera-iragazkien egiaztatzaileei eskaerak egitea baimentzen die aplikazioei. Aplikazio normalek ez lukete beharko."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"atzitu serie-atakak"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Jabeari serieko atakak atzitzeko aukera ematen dio SerialManager APIa erabilita."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"eduki-hornitzaileak kanpotik atzitzea"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Atzeratu egun bat"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aurreratu urtebete"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Atzeratu urtebete"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Aurreko hilabetea"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Hurrengo hilabetea"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Utzi"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ezabatu"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Hautatu minutuak"</string>
     <string name="select_day" msgid="7774759604701773332">"Hautatu hilabetea eta eguna"</string>
     <string name="select_year" msgid="7952052866994196170">"Hautatu urtea"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> hautatu da"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ezabatu da"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Laneko <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Aingura kentzeko, eduki ukituta Atzera eta Ikuspegi orokorra botoiak aldi berean."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Eskatu PIN kodea aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Bateriak gehiago iraun dezan, bateria-aurrezleak gailuaren funtzionamendua, dardara,  kokapen-zerbitzuak eta atzeko planoko datuen erabilera gehiena mugatzen ditu. Posta elektronikoa, mezuak eta sinkronizatzen diren gainerako zerbitzuak ez dira eguneratuko ireki ezean.\n\nGailua kargatzen ezarri orduko desaktibatzen da bateria-aurrezlea."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> arte iraungo du jarduerarik gabeko aldiak"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Jarduerarik gabeko denbora amaitu arte"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index babe1f0..767be9d 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"اعلان رومینگ خاموش"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"جستجوی سرویس"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"‏تماس از طریق Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"خاموش"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏Wi-Fi ترجیحی"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"شبکه سلولی ترجیحی"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"‏فقط Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: هدایت نشده"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> پس از <xliff:g id="TIME_DELAY">{2}</xliff:g> ثانیه"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه می‌دهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه می‌‌دهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"‏LED نشانگر انتقال داده، هنگام استفاده از دوربین غیرفعال شود"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"‏به یک برنامه سیستم از قبل نصب شده اجازه می‌دهد LED نشانگر استفاده از دوربین را غیرفعال کند."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"به یک برنامه کاربردی سیستم از قبل نصب شده اجازه می‌دهد رویدادهای سیستم را به سرویس دوربین ارسال کند."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"غیر فعال کردن دائم رایانهٔ لوحی"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"غیرفعالسازی دائم تلویزیون"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"تلفن بطور دائمی غیرفعال شود"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"‏شروع مستقیم راه‌اندازی تلویزیون CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"‏شروع مستقیم راه‌اندازی تلفن CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"‏به برنامه اجازه می‎دهد تا شرایط مقررات CDMA را شروع کند. برنامه‎های مخرب می‎توانند شرایط مقررات CDMA را در مواقع غیرضروری شروع کند."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"شروع راه‌اندازی سیم‌‌کارت"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"به برنامه امکان می‌دهد به درخواست‌های فعال‌سازی سیم‌کارت رسیدگی کند. برنامه می‌تواند به طور مستقیم فعال‌سازی را انجام دهد یا می‌تواند فعال‌سازی را به برنامه دیگری واگذار کند."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"کنترل اعلان‌های به‌روزرسانی مکان"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"‏به برنامه اجازه می‎دهد اعلانهای به‎روزرسانی موقعیت مکانی را از رادیو فعال/غیرفعال کند. برای استفاده برنامه‎های عادی نیست."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"دسترسی به مشخصات اعلام ورود"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"‏به برنامه امکان می‌دهد گواهی‌های DRM را حذف کند. نباید برای برنامه‌های عادی هیچ‌وقت لازم باشد."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"مقید به سرویس پیام‌رسانی شرکت مخابراتی"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"به کنترل‌کننده اجازه می‌دهد که به سطح بالای رابط کاربر سرویس پیام‌رسانی شرکت مخابراتی مقید شود. هرگز نباید برای برنامه‌های عادی مورد نیاز شود."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"تعامل با سرویس تعامل صوتی"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"به دارنده امکان می‌دهد با سرویس تعامل صوتی در حال حاضر فعال، تعامل داشته باشد. هرگز نباید برای برنامه‌های معمولی مورد نیاز باشد."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"تنظیم قوانین رمز ورود"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"کنترل طول و نوع نویسه‌هایی که در گذرواژه و پین قفل صفحه مجاز است."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"نمایش تلاش‌های قفل گشایی صفحه"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"به برنامه اجازه می‌دهد قابل نصب بودن بسته را تأیید کند."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"اتصال به یک تأیید کننده بسته"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"‏به دارنده اجازه می‎دهد تا تاییدکنندگان بسته را درخواست کند. برای برنامه‎های عادی نیاز نیست."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"تأیید فیلتر هدف"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"به برنامه اجازه می‌دهد بررسی کند که فیلتر هدف تأیید شده یا خیر."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ارتباط با یک بررسی‌کننده فیلتر هدف"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"به دارنده اجازه می‌دهد بررسی‌کننده فیلتر هدف را درخواست کند. هرگز نباید برای برنامه‌های عادی مورد نیاز شود."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاه‌های سریال"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"‏به دارنده اجازه می‌دهد با استفاده از SerialManager API به درگاه‌های سریال دسترسی داشته باشد."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"دسترسی خارجی به ارائه‌دهندگان محتوا"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"کاهش روز"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"افزایش سال"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"کاهش سال"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ماه قبل"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"ماه بعد"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"لغو"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"انتخاب دقیقه"</string>
     <string name="select_day" msgid="7774759604701773332">"انتخاب ماه و روز"</string>
     <string name="select_year" msgid="7952052866994196170">"انتخاب سال"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> انتخاب شد"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> حذف شد"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> محل کار"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"برای برداشتن پین این صفحه، هم‌زمان «بازگشت» و «نمای کلی» را لمس کنید و نگه دارید."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"درخواست کد پین قبل از برداشتن پین"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"درخواست الگوی باز کردن قفل قبل از برداشتن پین"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"درخواست گذرواژه قبل از برداشتن پین"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"برای کمک به بهبود ماندگاری باتری، ابزار صرفه‌جویی در مصرف باتری عملکرد دستگاهتان را کاهش می‌دهد و لرزش، سرویس‌های مبتنی بر مکان، و دسترسی به اکثر داده‌ها در پس‌زمینه را محدود می‌کند. ایمیل، پیام‌رسانی و برنامه‌های دیگری که به همگام‌سازی متکی هستند، تا زمانی که آن‌ها را باز نکنید نمی‌توانند به‌روز شوند.\n\nابزار صرفه‌جویی در مصرف باتری به صورت خودکار در هنگام شارژ شدن دستگاه خاموش می‌شود."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"تا زمانی که زمان استراحت در <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> به پایان برسد"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"تا زمان اتمام فرویش"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 76d3ba4..1f01b0c 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roaming-banneri pois käytöstä"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Etsitään signaalia"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-puhelut"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ei siirretty"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunnin päästä"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"poista lähetyksen merkkivalo käytöstä, kun kameraa käytetään"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Antaa valmiiksi asennetun järjestelmäsovelluksen poistaa käytöstä kameran käytössäolon merkkivalon."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Antaa valmiiksi asennetun järjestelmäsovelluksen lähettää kamerapalvelulle tietoja järjestelmätapahtumista."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"poista tabletti käytöstä lopullisesti"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"Poista televisio pysyvästi käytöstä"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"poista puhelin käytöstä pysyvästi"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"Käynnistä CDMA-television asetusten määrittäminen"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"aloita CDMA-puhelimen asetuksien määrittäminen"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Antaa sovelluksen aloittaa CDMA-määrityksen. Haitalliset sovellukset voivat aloittaa tarpeettoman CDMA-määrityksen."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"hallitse sijaintien päivitysilmoituksia"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Antaa sovelluksen ottaa käyttöön / poistaa käytöstä radion sijainninpäivitysilmoitukset. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"käyttää checkin-asetuksia"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Antaa sovelluksen poistaa DRM-varmenteita. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Operaattorin viestipalveluun sitoutuminen"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Antaa sovelluksen sitoutua operaattorin viestipalvelun ylätason liittymään. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"vuorovaikutus ääniohjauspalvelun kanssa"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Sallii vuorovaikutuksen aktiivisen ääniohjauspalvelun kanssa. Ei tavallisten sovellusten käyttöön."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Aseta salasanasäännöt"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Hallinnoi ruudun ruudun lukituksen salasanoissa ja PIN-koodeissa sallittuja merkkejä ja niiden pituutta."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Tarkkaile ruudun lukituksen poistoyrityksiä"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Antaa sovelluksen vahvistaa, että pakkaus on asennettavissa."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sitoudu paketin vahvistajaan"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"vahvista aikomussuodatin"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Antaa sovelluksen tarkistaa, onko aikomussuodatin vahvistettu vai ei."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"sitoudu aikomussuodattimen vahvistuspalveluun"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Antaa sovelluksen tehdä aikomussuodattimen vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"käytä ulkoisia sisällöntarjoajia"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Vähennä päivien määrää."</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Lisää vuosien määrää."</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Vähennä vuosien määrää."</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Edellinen kuukausi"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Seuraava kuukausi"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Peruuta"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Poista"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Valitse minuutit"</string>
     <string name="select_day" msgid="7774759604701773332">"Valitse kuukausi ja päivä"</string>
     <string name="select_year" msgid="7952052866994196170">"Valitse vuosi"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> on valittu"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> poistettiin"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (työ)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Poista näytön kiinnitys painamalla Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pyydä PIN-koodi ennen irrotusta"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pyydä salasana ennen irrotusta"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Jos haluat parantaa akun kestoa, virransäästö vähentää laitteesi suorituskykyä ja rajoittaa värinää, sijaintipalveluita ja useimpia taustatietoja. Sähköposti, viestit ja muut synkronointiin perustuvat sovellukset eivät välttämättä päivity, ellet avaa niitä.\n\nVirransäästö poistuu käytöstä automaattisesti, kun laitteesi latautuu."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Käyttökatkos päättyy klo <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Vapaa-aikasi päättymiseen saakka"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 81bd0653..9db0eb1 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Bannière d\'itinérance désactivée"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Recherche des services disponibles"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Appels Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"désactiver l\'indicateur d\'émission LED lorsque la caméra est en cours d\'utilisation"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet à une application système préinstallée de désactiver l\'indicateur LED d\'utilisation de la caméra."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permet à une application système préinstallée d\'envoyer au service de l\'appareil photo des événements relatifs au système."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"désactiver définitivement la tablette"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"désactiver définitivement le téléviseur"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"désactiver définitivement le téléphone"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"lancer directement la configuration du téléviseur par CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"démarrer directement la configuration du téléphone CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permet à l\'application de lancer le déploiement CDMA. Des applications malveillantes sont susceptibles de le lancer inutilement."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"contrôler les notifications de mise à jour de la position géographique"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet à l\'application d\'activer ou de désactiver les notifications de mise à jour de la position à partir du signal radio. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"accéder aux propriétés d\'enregistrement"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permet à une application de supprimer les certificats GDN. Cela ne devrait jamais être nécessaire pour des applications normales."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"s\'associer à un service de messagerie d\'un fournisseur"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permet à l\'application autorisée de s\'associer à l\'interface de plus haut niveau d\'un service de messagerie d\'un fournisseur. Les applications standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interagir avec service d\'interaction vocale"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permet à l\'utilisateur d\'interagir avec le service d\'interaction vocale actif. Cette option ne devrait jamais être nécessaire pour les applications standards."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les NIP de verrouillage de l\'écran."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un paquet peut être installé."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"s\'associer à un vérificateur de paquet"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de paquet. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"vérifier le filtre d\'intention"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permet à l\'application de vérifier si un filtre d\'intention est validé ou non."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"s\'associer à un vérificateur de filtre d\'intention"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de filtres d\'intention. Les applications standards ne devraient jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accès externe aux fournisseurs de contenu"</string>
@@ -1241,7 +1262,7 @@
     <string name="whichViewApplicationNamed" msgid="2286418824011249620">"Ouvrir avec %1$s"</string>
     <string name="whichEditApplication" msgid="144727838241402655">"Modifier avec"</string>
     <string name="whichEditApplicationNamed" msgid="1775815530156447790">"Modifier avec %1$s"</string>
-    <string name="whichSendApplication" msgid="6902512414057341668">"Partager avec"</string>
+    <string name="whichSendApplication" msgid="6902512414057341668">"Partager"</string>
     <string name="whichSendApplicationNamed" msgid="2799370240005424391">"Partager avec %1$s"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Sélectionner une application pour l\'écran d\'accueil"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Utiliser %1$s comme écran d\'accueil"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Jour précédent"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Année suivante"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Année précédente"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Le mois précédent"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Le mois prochain"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Sélectionnez les minutes"</string>
     <string name="select_day" msgid="7774759604701773332">"Sélectionnez un mois et un jour"</string>
     <string name="select_year" msgid="7952052866994196170">"Sélectionnez une année"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"« <xliff:g id="ITEM">%1$s</xliff:g> » a été sélectionné"</string>
     <string name="deleted_key" msgid="7659477886625566590">"« <xliff:g id="KEY">%1$s</xliff:g> » a été supprimé"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage de cet écran, appuyez de manière prolongée sur Retour et Aperçu simultanément."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le NIP avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la pile, la fonction d\'économie d\'énergie réduit les performances de votre appareil et limite la vibration, les services de localisation ainsi que la plupart des données en arrière-plan. Les applications Courriel, Messages et d\'autres qui reposent sur la synchronisation ne peuvent pas se mettre à jour, sauf si vous les ouvrez. \n\n L\'économiseur d\'énergie se désactive automatiquement lorsque votre appareil est en charge."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Jusqu\'à ce que le temps d\'arrêt se termine à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Jusqu\'à la fin du temps d\'arrêt"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 115c567..92b9bfc 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Bannière d\'itinérance désactivée"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Recherche des services disponibles"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Appels Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : non transféré"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : <xliff:g id="DIALING_NUMBER">{1}</xliff:g> au bout de <xliff:g id="TIME_DELAY">{2}</xliff:g> secondes"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"désactiver l\'indicateur d\'émission LED lorsque la caméra est en cours d\'utilisation"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permet à une application système préinstallée de désactiver l\'indicateur LED d\'utilisation de la caméra."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permet à une application système préinstallée d\'envoyer au service de l\'appareil photo des événements relatifs au système."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"désactiver définitivement la tablette"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"désactiver le téléviseur de manière définitive"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"désactiver définitivement le téléphone"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"lancer directement la configuration CDMA du téléviseur"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"démarrer directement la configuration du téléphone CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permet à l\'application de lancer le déploiement CDMA. Des applications malveillantes sont susceptibles de le lancer inutilement."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"Contrôle des notifications de mise à jour de position géo."</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permet à l\'application d\'activer ou de désactiver les notifications de mise à jour de la position à partir du signal radio. Les applications standards ne doivent pas utiliser cette fonctionnalité."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"Accès aux propriétés d\'enregistrement"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permet à une application de supprimer les certificats de GDN. Ne devrait jamais être nécessaire pour les applications standards."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"s\'associer au service SMS/MMS d\'un opérateur"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permettre à l\'application de s\'associer à l\'interface de niveau supérieur du service SMS/MMS d\'un opérateur. Ne devrait jamais être nécessaire pour les applications standards."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interagir avec le service d\'interaction vocale"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permettre à l\'application autorisée d\'interagir avec le service d\'interaction vocale actif. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Gérer le nombre et le type de caractères autorisés dans les mots de passe et les codes d\'accès de verrouillage de l\'écran"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un package peut être installé."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associer à un vérificateur de package"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"valider le filtre d\'intention"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permet à l\'application de vérifier si un filtre d\'intention est validé ou non."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"s\'associer pour valider filtre d\'intention"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permet à l\'application autorisée de demander la validation des filtres d\'intention. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accès externe fournisseurs de contenu"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Jour précédent"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Année suivante"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Année précédente"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mois précédent"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mois suivant"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuler"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Supprimer"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Sélectionner des minutes"</string>
     <string name="select_day" msgid="7774759604701773332">"Sélectionner un mois et un jour"</string>
     <string name="select_year" msgid="7952052866994196170">"Sélectionner une année"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"\"<xliff:g id="ITEM">%1$s</xliff:g>\" sélectionné"</string>
     <string name="deleted_key" msgid="7659477886625566590">"\"<xliff:g id="KEY">%1$s</xliff:g>\" supprimé"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pour annuler l\'épinglage, appuyez de manière prolongée et simultanée sur \"Retour\" et \"Aperçu\"."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Demander le code PIN avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Pour améliorer l\'autonomie de la batterie, l\'économiseur de batterie réduit les performances de votre appareil, et il désactive le vibreur, les services de localisation et la plupart des données en arrière-plan. La messagerie électronique, les SMS/MMS et les autres applications basées sur la synchronisation ne sont mises à jour que si vous les ouvrez.\n\nL\'économiseur de batterie s\'éteint automatiquement lorsque votre appareil est en charge."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Jusqu\'à ce que le temps d\'arrêt se termine à <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Jusqu\'à la fin du temps d\'arrêt"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index a282039..a84c36d 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner de itinerancia desactivado"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Buscando servizo"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Chamadas por wifi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desactivado"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wifi preferida"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Móbil preferido"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Só wifi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: non desviada"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> tras <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desactivar LED indicador de transmisión cando se está utilizando a cámara"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite a unha aplicación do sistema preinstalada desactivar o LED indicador de uso da cámara."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permite a unha aplicación do sistema preinstalada enviar eventos do sistema do servizo da cámara."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desactivar o tablet permanentemente"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"desactivar a televisión permanentemente"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"desactivar o teléfono permanentemente"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"iniciar directamente a configuración CDMA da televisión"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar directamente a configuración CDMA do teléfono"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite á aplicación iniciar o aprovisionamento CDMA. É posible que aplicacións maliciosas inicien o aprovisionamento CDMA de forma innecesaria."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"iniciar configuración da tarxeta SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Permite que a aplicación xestione solicitudes de activación da SIM. A aplicación pode realizar directamente a activación ou pode delegar noutra aplicación."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar as notificacións de actualización de localización"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite á aplicación activar/desactivar as notificacións de actualización de localización desde a radio. As aplicacións normais non deben utilizar este permiso."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"acceder ás propiedades de rexistro"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite a unha aplicación eliminar os certificados DRM. As aplicacións normais non o deberían precisar nunca."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular a un servizo de mensaxería"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite ao propietario vincularse á interface de nivel superior dun servizo de mensaxería. As aplicacións normais non deberían necesitar este permiso."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interactuar co servizo de interacción de voz"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permite que o propietario interactúe co servizo de interacción de voz activo actualmente. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Establecer as normas de contrasinal"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla a lonxitude e os caracteres permitidos nos contrasinais e nos PIN de bloqueo da pantalla."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Supervisar os intentos de desbloqueo da pantalla"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite á aplicación verificar se un paquete é instalable."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a un verificador de paquetes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao propietario realizar solicitudes de verificadores de paquetes. As aplicacións normais non deberían necesitar este permiso."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intento"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite á aplicación comprobar se un filtro de intento está verificado ou non."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ligar a verificador de filtro de intento"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite ao propietario realizar solicitudes de verificadores de filtros de intento. As aplicacións normais non deberían necesitar este permiso."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acceder a portos serie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o propietario poida acceder aos portos serie usando a API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acceder a provedores de contido externamente"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reducir día"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reducir ano"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mes anterior"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mes seguinte"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eliminar"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Seleccionar minutos"</string>
     <string name="select_day" msgid="7774759604701773332">"Seleccionar mes e día"</string>
     <string name="select_year" msgid="7952052866994196170">"Seleccionar ano"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seleccionado"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar a pantalla, mantén premido Atrás e Visión xeral ao mesmo tempo."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicitar un PIN antes de soltar a pantalla"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicitar un padrón de desbloqueo antes de soltar a pantalla"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicitar un contrasinal antes de soltar a pantalla"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Para axudar a mellorar a duración da batería, a función aforro de batería reduce o rendemento do teu dispositivo e limita a vibración, os servizos de localización e a maioría dos datos en segundo plano. É posible que o correo electrónico, as mensaxes e outras aplicacións que dependen da sincronización non se actualicen a menos que os abras. \n\nA función aforro de batería desactívase automaticamente cando pos a cargar o teu dispositivo."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Ata que remate o tempo de inactividade ás <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Ata que remate o tempo de inactividade"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 943ed28..579de59 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"रोमिंग बैनर बंद"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"सेवा खोज रहा है"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"वाई-फ़ाई कॉलिंग"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"बंद"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"वाई-फ़ाई को प्राथमिकता"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"सेल्‍युलर को प्राथमिकता"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"केवल वाई-फ़ाई"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अग्रेषित नहीं किया गया"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकंड के बाद"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स  को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स  को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"कैमरा उपयोग में होने पर संचारण संकेतक LED अक्षम करें"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पहले से इंस्टॉल किए गए सिस्टम ऐप्स  को कैमरे को संकेतक LED का उपयोग करने से अक्षम करती है."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"पहले से इंस्टॉल किए गए सिस्टम ऐप्लिकेशन को कैमरा सेवा सिस्टम ईवेंट भेजने की अनुमति देती है."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"स्‍थायी रूप से टेबलेट अक्षम करें"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"टीवी को स्‍थायी रूप से अक्षम करना"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"फ़ोन को स्‍थायी रूप से अक्षम करें"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA टीवी सेटअप को सीधे प्रारंभ करना"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"सीधे CDMA फ़ोन सेटअप प्रारंभ करें"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"ऐप्स को CDMA प्रावधान प्रारंभ करने देता है. दुर्भावनापूर्ण ऐप्स अनावश्‍यक रूप से CDMA प्रावधान प्रारंभ कर सकते हैं."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM कार्ड सेटअप प्रारंभ करें"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"ऐप को SIM सक्रियण अनुरोधों को प्रबंधित करने देता है. एेप सीधे सक्रियण निष्‍पादित कर सकता है या अन्‍य ऐप को सौंप सकता है."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"स्‍थान के बारे में नई जानकारी की नोटिफिकेशन को नियंत्रित करें"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"एप को रेडियो से स्‍थान के बारे में नई जानकारी की सूचनाएं सक्षम/अक्षम करने देता है. सामान्‍य ऐप्स द्वारा उपयोग करने के लिए नहीं."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"चेकइन गुणों में पहुंचें"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"एप्‍लिकेशन को DRM प्रमाणपत्रों को निकालने देता है. सामान्य ऐप्स के लिए कभी भी आवश्यकता नहीं होनी चाहिए."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"किसी वाहक संदेश सेवा से आबद्ध करें"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"धारक को किसी वाहक संदेश सेवा के शीर्ष-स्‍तरीय इंटरफ़ेस से आबद्ध होने देती है. सामान्‍य ऐप्‍स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ध्वनि सहभागिता सेवा के साथ सहभागिता करें"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"धारक को वर्तमान में सक्रिय ध्वनि सहभागिता सेवा के साथ सहभागिता करने की अनुमति देती है. सामान्य ऐप्स के लिए इसकी आवश्यकता कभी नहीं होनी चाहिए."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करें"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्‍क्रीन लॉक पासवर्ड तथा पिन की लंबाई और उसमें अनुमत वर्णों को नियंत्रित करें."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्‍क्रीन-अनलॉक के प्रयासों पर निगरानी रखें"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्‍लि‍केशन को इंस्‍टॉल करने योग्‍य पैकेज सत्‍यापि‍त करने देता है."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति‍ देता है. सामान्‍य ऐप्स के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"लक्ष्य फ़िल्टर सत्यापित करें"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ऐप को जांच करने देती है कि कोई लक्ष्य फ़िल्टर सत्यापित है या नहीं."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"लक्ष्य फ़िल्टर प्रमाणक से आबद्ध करें"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"धारक को लक्ष्य फ़िल्टर प्रमाणक के अनुरोध की अनुमति देती है. सामान्य ऐप्स के लिए कभी भी आवश्यक नहीं होना चाहिए."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"बाह्य रूप से सामग्री प्रदाताओं पर पहुंच"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिन कम करें"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढ़ाएं"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कम करें"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"पिछला महीना"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"अगला महीना"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"अभी नहीं"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटाएं"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"मिनट चुनें"</string>
     <string name="select_day" msgid="7774759604701773332">"माह और दिन चुनें"</string>
     <string name="select_year" msgid="7952052866994196170">"वर्ष चुनें"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> चयनित"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> को हटा दिया गया"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्यस्थल का <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"इस स्क्रीन को अनपिन करने के लिए, एक ही समय में वापस जाएं और अवलोकन को स्पर्श करके रखें."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करने से पहले पिन के लिए पूछें"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"अनपिन करने से पहले अनलॉक पैटर्न के लिए पूछें"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"अनपिन करने से पहले पासवर्ड के लिए पूछें"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"बैटरी जीवन काल को बेहतर बनाने में सहायता के लिए, बैटरी सेवर आपके डिवाइस के प्रदर्शन को कम कर देता है और कंपन, स्‍थान सेवाओं और अधिकांश पृष्‍ठभूमि डेटा को सीमित कर देता है. हो सकता है कि ईमेल, संदेश सेवा तथा समन्‍वयन पर आधारित अन्‍य ऐप्‍स तब तक ना खुलें जब तक कि आप उन्‍हें नहीं खोलते.\n\nजब आपका डिवाइस चार्ज हो रहा होता है तो बैटरी सेवर अपने आप बंद हो जाता है."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"जब तक कि <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> बजे आपका डाउनटाइम समाप्‍त न हो"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"आपका बंद रहने का समय समाप्‍त होने तक"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bc3f839..f629d4a 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -125,9 +125,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Isključen je natpis roaminga"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Pretraživanje usluge"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi pozivi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nije proslijeđeno"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> nakon <xliff:g id="TIME_DELAY">{2}</xliff:g> s"</string>
@@ -586,6 +596,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"onemogućavanje lampice pokazivača prijenosa kada je fotoaparat u upotrebi"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Omogućuje unaprijed instaliranim aplikacijama sustava onemogućavanje lampice pokazivača upotrebe fotoaparata."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Omogućuje unaprijed instaliranim aplikacijama sustava slanje događaja sustava usluge fotoaparata."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trajno onemogući tabletni uređaj"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"trajno onemogućivanje televizora"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"trajno onemogućavanje telefona"</string>
@@ -634,6 +645,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"izravno pokretanje postavljanja televizora za CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"izravno pokretanje postavke CDMA telefona"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Aplikaciji omogućuje pokretanje dodjele CDMA. Zlonamjerne aplikacije mogu nepotrebno pokrenuti dodjelu CDMA."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"obavijesti o ažuriranju kontrolne lokacije"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Omogućuje aplikaciji omogućavanje/onemogućavanje obavijesti o ažuriranju lokacije s radija. Nije namijenjena uobičajenim aplikacijama."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"pristup svojstvima prijave"</string>
@@ -840,6 +855,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Omogućuje aplikaciji uklanjanje DRM certifikata. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"povezivanje s uslugom mobilnog operatera za slanje poruka"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Omogućuje nositelju povezivanje sa sučeljem najviše razine usluge mobilnog operatera za slanje poruka. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interakcija s uslugom glasovne interakcije"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Omogućuje korisniku interakciju s trenutačno aktivnom uslugom glasovne interakcije. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Postavi pravila zaporke"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Upravlja duljinom i znakovima koji su dopušteni u zaporkama i PIN-ovima zaključavanja zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Nadgledaj pokušaje otključavanja zaslona"</string>
@@ -1137,6 +1154,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogućuje da provjeri je li paket moguće instalirati."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vezano uz paketnu provjeru"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"potvrditi filtar namjere"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Omogućuje aplikaciji da provjeri je li filtar namjere potvrđen."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vezati se uz potvrdu filtara namjere"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Omogućuje nositelju zahtijevanje potvrde filtara namjere. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"pristup pružateljima sadržaja izvana"</string>
@@ -1569,6 +1590,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Smanjenje dana"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povećanje godine"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Smanjenje godine"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prethodni mjesec"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Sljedeći mjesec"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Odustani"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
@@ -1822,7 +1845,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Odaberite minute"</string>
     <string name="select_day" msgid="7774759604701773332">"Odaberite mjesec i dan"</string>
     <string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Odabrana je stavka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Izbrisan je broj <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za posao"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkvačili ovaj zaslon, istovremeno dodirnite i zadržite Natrag i Pregled."</string>
@@ -1833,6 +1855,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Traži PIN radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Traži uzorak za otključavanje radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Traži zaporku radi otkvačivanja"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se produljilo trajanje baterije, ušteda baterije smanjuje rad uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Aplikacije za e-poštu, slanje poruka i druge aplikacije koje se oslanjaju na sinkronizaciju možda se neće ažurirati ako ih ne otvorite.\n\nUšteda baterije isključuje se automatski dok se uređaj puni."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Dok razdoblje zastoja ne završi u <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Do završetka prekida rada"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index df2d876..f2a91b5 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Barangolást jelző szalaghirdetés kikapcsolva"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Szolgáltatás keresése"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-hívás"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nincs átirányítva"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> másodperc után"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"átviteljelző LED letiltása, ha a kamera használatban van"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Lehetővé teszi egy előre telepített rendszeralkalmazás számára, hogy letiltsa a kamerahasználatot jelző LED-et."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Lehetővé teszi egy előre telepített rendszeralkalmazás számára, hogy a elküldje a kameraszolgáltatási értesítéseket a rendszerszintű eseményekről."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"a táblagép végleges deaktiválása"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"a tévé teljes letiltása"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"telefon végleges letiltása"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"a CDMA tévébeállítás közvetlen elindítása"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA-telefonbeállítás közvetlen elindítása"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Lehetővé teszi az alkalmazás számára a CDMA-szolgáltatás elindítását. A rosszindulatú alkalmazások szükségtelenül is elindíthatják ezt."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"helyaktualizálási értesítések vezérlése"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Lehetővé teszi az alkalmazás számára a rádiótól érkező helyaktualizálási értesítések engedélyezését/letiltását. Normál alkalmazások nem használhatják."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"hozzáférés a bejelentkezési tulajdonságokhoz"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Lehetővé teszi, hogy az alkalmazás eltávolítsa a DRM-tanúsítványokat. A normál alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"kapcsolódás egy üzenetszolgáltatáshoz"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Lehetővé teszi, hogy a tulajdonos kapcsolódjon egy üzenetszolgáltatás legfelső szintű kezelőfelületéhez. A normál alkalmazásoknak erre soha nincs szükségük."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"együttműködés a hanginterakciós szolgáltatással"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Az engedéllyel rendelkező együttműködhet a jelenleg aktív hanginterakciós szolgáltatással. Az átlagos alkalmazásoknak erre soha nincs szükségük."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Jelszavakkal kapcsolatos szabályok beállítása"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"A képernyőzár jelszavaiban és PIN kódjaiban engedélyezett karakterek és hosszúság vezérlése."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Képernyőzár-feloldási kísérletek figyelése"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lehetővé teszi az alkalmazás számára, hogy ellenőrizze, egy csomag telepíthető-e."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"egy csomaghitelesítőhöz kötődnek"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"„intent filter” hitelesítése"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Lehetővé teszi annak ellenőrzését egy alkalmazás számára, hogy egy „intent filter” hitelesítve van-e."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"rögzítés egy „intent filter” hitelesítőhöz"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Lehetővé teszi, hogy a tulajdonos kéréseket kezdeményezzen az „intent filter” hitelesítőkkel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"tartalomszolgáltatók külső elérése"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Dátum értékének csökkentése"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Év értékének növelése"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Év értékének csökkentése"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Előző hónap"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Következő hónap"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Mégse"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Perc kiválasztása"</string>
     <string name="select_day" msgid="7774759604701773332">"Válassza ki a hónapot és a napot"</string>
     <string name="select_year" msgid="7952052866994196170">"Válassza ki az évet"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> kiválasztva"</string>
     <string name="deleted_key" msgid="7659477886625566590">"A(z) <xliff:g id="KEY">%1$s</xliff:g> érték törölve"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Munkahelyi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"A képernyő rögzítésének feloldásához tartsa lenyomva a Vissza és az Áttekintés lehetőséget egyszerre."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"PIN kód kérése a rögzítés feloldásához"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Feloldási minta kérése a rögzítés feloldásához"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Jelszó kérése a rögzítés feloldásához"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Az akkumulátoridő növelése érdekében az energiatakarékos mód csökkenti az eszköz teljesítményét, és korlátozza a rezgést, a helyszolgáltatásokat, valamint a legtöbb háttéradatot is. Előfordulhat, hogy azok az e-mail-, üzenetküldő és egyéb alkalmazások, amelyek szinkronizálására számít, csak akkor frissítenek, ha megnyitja azokat.\n\nAz energiatakarékos mód automatikusan kikapcsol, ha eszköze töltőn van."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Amíg az állásidő véget nem ér ekkor: <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Amíg az inaktivitás véget nem ér"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 9a59303..e680f5e 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Ռոումինգի ազդերիզն անջատված է"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Ծառայության որոնում..."</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Զանգեր Wi-Fi-ի միջոցով"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. Չի վերահասցեավորվել"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>. <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> վայրկյանից"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"անջատել փոխանցող LED ցուցիչը, երբ ֆոտոխցիկը օգտագործվում է"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Թույլ է տալիս նախապես տեղադրված համակարգային ծրագրին անջատել ֆոտոխցիկի օգտագործման LED ցուցիչը:"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Նախապես տեղադրված համակարգային հավելվածին թույլ է տալիս խցիկի ծառայությանն ուղարկել համակարգի իրադարձությունները:"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"մշտապես անջատել գրասալիկը"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"մշտապես անջատել հեռուստացույցը"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ընդմիշտ կասեցնել հեռախոսը"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"ուղղակիորեն մեկնարկել CDMA-ի կարգավորումը հեռուստացույցի վրա"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ուղղակիորեն սկսել CDMA հեռախոսի կարգավորումը"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Թույլ է տալիս հավելվածին մեկնարկել CDMA-ի տրամադրումը: Վնասարար հավելվածները կարող են անտեղի սկսել CDMA-ի տրամադրում:"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"վերահսկել տեղանքի թարմացման ծանուցումները"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Թույլ է տալիս հավելվածին միացնել կամ անջատել տեղանքի թարմացման ծանուցումները ռադիոյից: Սովորական հավելվածների օգտագործման համար չէ:"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"մուտք գործել գրանցանշման կարգավորումներ"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Ծրագրին թույլ է տալիս հեռացնել DRM վկայագրեր: Սովորական ծրագրերի համար երբեք պետք չի գալիս:"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Կապակցում օպերատորի հաղորդագրությունների ծառայության հետ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Թույլ է տալիս տիրոջը կապվել օպերատորի հաղորդագրությունների ծառայության վերին մակարդակի միջերեսի հետ: Սա երբեք չի պահանջվում սովորական հավելվածների համար:"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"փոխազդել ձայնային փոխազդման ծառայության հետ"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Թույլ է տալիս սեփականատիրոջը փոխազդել ընթացիկ ձայնային փոխազդման ծառայության հետ: Չի պահանջվում սովորական հավելվածների դեպքում:"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Սահմանել գաղտնաբառի կանոնները"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Կառավարել էկրանի ապակողպման գաղտնաբառերի և PIN կոդերի թույլատրելի երկարությունն ու գրանշանները:"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Վերահսկել էկրանի ապակողպման փորձերը"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Թույլ է տալիս հավելվածին հաստատել, որ փաթեթը տեղադրելի է:"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"միանալ փաթեթի ստուգիչին"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Թույլ է տալիս սեփականատիրոջը փաթեթի ստուգիչների հարցում կատարել: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ստուգել ինտենտ-զտիչը"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Հավելվածին թույլ է տալիս ճշտել՝ ստուգված է արդյոք ինտենտ-զտիչը, թե ոչ:"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"կապվել ինտենտ-զտիչի ստուգիչի հետ"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Թույլ է տալիս կատարել հարցումներ ինտենտ-զտիչի ստուգիչների վերաբերյալ: Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի:"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"մուտք գործել հաջորդական միացքներ"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Թույլ է տալիս սեփականատիրոջը մուտք գործել հաջորդական միացքներ` օգտագործելով SerialManager API-ը:"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"դրսից մատչել բովանդակություն տրամադրողներին"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Նվազեցնել օրը"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Աճեցնել տարին"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Նվազեցնել տարին"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Նախորդ ամիս"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Հաջորդ ամիս"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Չեղարկել"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ջնջել"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Ընտրեք րոպեն"</string>
     <string name="select_day" msgid="7774759604701773332">"Ընտրեք ամիսն ու օրը"</string>
     <string name="select_year" msgid="7952052866994196170">"Ընտրեք տարին"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Ընտրված է <xliff:g id="ITEM">%1$s</xliff:g> տարրը"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> թիվը ջնջված է"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Աշխատանքային <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Այս էկրան ապամրացնելու համար միաժամանակ հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Ապաամրացնելուց առաջ հարցնել PIN-կոդը"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Ապաամրացնելուց առաջ հարցնել ապակողպող նախշը"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Ապաամրացնելուց առաջ հարցնել գաղտնաբառը"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Մարտկոցի աշխատանքի ժամկետը երկարացնելու նպատակով, մարտկոցի էներգիայի խնայման գործառույթը սահմանափակում է սարքի աշխատանքը, թրթռոցը, տեղադրության ծառայությունները և հետնաշերտում աշխատող շատ գործընթացներ: Էլփոստը, հաղորդագրությունների փոխանակումը և տվյալների համաժամեցումից կախված այլ հավելվածները կարող են չթարմացվել, եթե դուք դրանք չգործարկեք:\n\nԵրբ ձեր սարքը լիցքավորվում է, մարտկոցի էներգիայի խնայման գործառույթն ինքնաշխատորեն անջատվում է:"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Մինչև ձեր ժամանակն ավարտվի ժամը <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Մինչև անգործունության ժամանակն ավարտվի"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index f1775d0..20a6924 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Spanduk Roaming Mati"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Mencari layanan"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Panggilan Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Nonaktif"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi dipilih"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Seluler dipilih"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Khusus Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Tidak diteruskan"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> setelah <xliff:g id="TIME_DELAY">{2}</xliff:g> detik"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"nonaktifkan LED indikator transmisi saat kamera digunakan"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Izinkan aplikasi sistem yang sudah dipasang sebelumnya menonaktifkan LED indikator penggunaan kamera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Mengizinkan aplikasi sistem yang sudah dipasang sebelumnya mengirim peristiwa sistem layanan kamera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"noaktifkan tablet secara permanen"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"nonaktifkan TV secara permanen"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"nonaktifkan ponsel secara permanen"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"langsung mulai penyiapan TV CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"mulai penyiapan ponsel CDMA secara langsung"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Mengizinkan apl memulai penyediaan CDMA. Apl berbahaya dapat memulai penyediaan CDMA yang tidak perlu."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"mulai penyiapan kartu SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Mengizinkan aplikasi menangani permintaan aktivasi SIM. Aplikasi dapat langsung melakukan aktivasi atau mendelegasikan ke aplikasi lain."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"mengontrol pemberitahuan pembaruan lokasi"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Mengizinkan apl mengaktifkan/menonaktifkan pemberitahuan pembaruan lokasi dari radio. Tidak untuk digunakan oleh apl normal."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"akses properti check in"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Memungkinkan aplikasi membuang sertifikat DRM. Tidak pernah dibutuhkan untuk aplikasi normal."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ikat ke layanan perpesanan operator"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Mengizinkan operator untuk mengikat ke antarmuka tingkat tinggi dari suatu layanan perpesanan operator. Fitur ini seharusnya tidak diperlukan oleh aplikasi normal."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"berinteraksi dengan layanan interaksi suara"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Mengizinkan pemegang berinteraksi dengan layanan interaksi suara yang saat ini aktif. Tidak pernah diperlukan oleh aplikasi normal."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setel aturan sandi"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Mengontrol panjang dan karakter yang diizinkan dalam sandi dan PIN kunci layar."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Upaya pembukaan kunci layar monitor"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Mengizinkan apl memverifikasi bahwa suatu paket dapat dipasang."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"mengikat ke pemverifikasi paket"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifikasi maksud filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Mengizinkan aplikasi memeriksa apakah maksud filter diverifikasi atau tidak."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ikat ke pemverifikasi maksud filter"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Mengizinkan pemegangnya mengajukan permintaan pemverifikasi maksud filter. Tidak diperlukan untuk aplikasi normal."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"mengakses penyedia konten dari luar"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kurangi hari"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tambah tahun"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Kurangi tahun"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Bulan sebelumnya"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Bulan berikutnya"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Hapus"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Pilih menit"</string>
     <string name="select_day" msgid="7774759604701773332">"Pilih bulan dan hari"</string>
     <string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> dipilih"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dihapus"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kantor <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk melepas pin layar ini, sentuh lama tombol Kembali dan Ringkasan secara bersamaan."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Meminta PIN sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Meminta pola pembukaan kunci sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Meminta sandi sebelum melepas sematan"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan kebanyakan data latar belakang. Email, perpesanan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hingga waktu perbaikan Anda berakhir pukul <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hingga waktu non-operasional berakhir"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 0797db1..674d179 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Slökkt á reikiborða"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Leitar að þjónustu"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi símtöl"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ekki áframsent"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> eftir <xliff:g id="TIME_DELAY">{2}</xliff:g> sekúndur"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"slökkva á gaumljósi flutnings þegar myndavél er í notkun"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Leyfir foruppsettu kerfisforriti að gera gaumljós myndavélarinnar óvirkt."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Leyfir foruppsettu kerfisforriti að senda myndavélarþjónustunni kerfisatvik."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"gera spjaldtölvuna varanlega óvirka"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"gera sjónvarpið varanlega óvirkt"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"gera símann varanlega óvirkan"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"ræsa CDMA-uppsetningu sjónvarps beint"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ræsa CDMA-uppsetningu síma beint"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Leyfir forriti að ræsa CDMA-úthlutun. Spilliforrit geta ræst CDMA-úthlutun að óþörfu."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"stjórna tilkynningum um staðsetningaruppfærslur"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Leyfir forriti að kveikja/slökkva á uppfærslutilkynningum um staðsetningu frá loftnetinu. Ekki ætlað venjulegum forritum."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"aðgangur að mætingareigindum"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Leyfir forriti að fjarlægja DRM-vottorð. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bindast skilaboðaþjónustu símafyrirtækis"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Leyfir forriti að bindast efsta viðmótslagi skilaboðaþjónustu símafyrirtækis. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"nota raddsamskiptaþjónustu"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Leyfir handhafa að nota virka raddsamskiptaþjónustu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setja reglur um aðgangsorð"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stjórna lengd og fjölda stafa í aðgangsorðum og PIN-númerum skjáláss."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Fylgjast með tilraunum til að taka skjáinn úr lás"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leyfir forriti að staðfesta að hægt sé að setja upp pakka."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bindast pakkasannvottun"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Leyfir handhafa að búa til beiðnir fyrir pakkastaðfestingu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"staðfesta ásetningssíu"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Leyfir forriti að athuga hvort ásetningssía er staðfest eða ekki."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"bindast staðfestingu ásetningssíu"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Leyfir handhafa að búa til beiðnir fyrir staðfestingu ásetningssíu. Ætti aldrei að vera nauðsynlegt fyrir venjuleg forrit."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"aðgangur að raðtengjum"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Leyfir forriti að fá aðgang að raðtengjum með forritaskilum SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ytri aðgangur að efnisveitum"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Niður um dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Upp um ár"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Niður um ár"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Fyrri mánuður"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Næsti mánuður"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hætta við"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Eyða"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Veldu mínútur"</string>
     <string name="select_day" msgid="7774759604701773332">"Veldu mánuð og dag"</string>
     <string name="select_year" msgid="7952052866994196170">"Veldu ár"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> valið"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eytt"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> í vinnu"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Til að taka lásinn af þessari skjámynd skaltu halda inni Til baka og Yfirliti samtímis."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Biðja um PIN-númer til að losa"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Biðja um opnunarmynstur til að losa"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Biðja um aðgangsorð til að losa"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Til að auka endingu rafhlöðunnar mun orkusparnaður draga úr afköstum tækisins og takmarka titring, staðsetningarþjónustu og megnið af bakgrunnsgögnum. Ekki er víst að tölvupóstur, skilaboð og önnur forrit sem reiða sig á samstillingu uppfærist nema þú opnir þau.\n\nSjálfkrafa er slökkt á orkusparnaði þegar tækið er í hleðslu."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Þangað til niðritíma lýkur, <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Þar til niðritíma lýkur"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 0269cc7..f64ac24 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner roaming disattivato"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Ricerca servizio"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Chiamate Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: inoltro non effettuato"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> dopo <xliff:g id="TIME_DELAY">{2}</xliff:g> secondi"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"disabilitazione del LED di indicazione della trasmissione quando la fotocamera è in uso"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Consente a un\'applicazione di sistema preinstallata di disabilitare il LED che indica l\'utilizzo della fotocamera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Consente a un\'applicazione di sistema preinstallata di inviare eventi di sistema al sistema della fotocamera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"disattivazione definitiva tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"disattivazione definitiva della TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"disattivazione telefono"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"avvio diretto della configurazione della TV CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"avviare direttamente la configurazione del telefono CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Consente all\'applicazione di avviare il servizio di provisioning CDMA. Le applicazioni dannose potrebbero avviare il servizio di provisioning CDMA quando non è necessario."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controllo notifiche aggiornamento posizione"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Consente all\'applicazione di abilitare/disabilitare le notifiche di aggiornamento sulla posizione dal segnale radio. Da non usare per normali applicazioni."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"accesso a proprietà di archiviazione"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Consente a un\'applicazione di rimuovere certificati DRM. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"associazione a un servizio di messaggi dell\'operatore"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Consente l\'associazione di un servizio di messaggi dell\'operatore all\'interfaccia principale. Non dovrebbe mai essere necessaria per le normali applicazioni."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interazione con il servizio di interazione vocale"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Consente al titolare di interagire con il servizio di interazione vocale attivo. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Impostazione regole password"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlla la lunghezza e i caratteri ammessi nelle password e nei PIN del blocco schermo."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Controllo tentativi di sblocco dello schermo"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Consente all\'applicazione di verificare se un pacchetto è installabile."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associazione a verifica pacchetto"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifica filtro di intent"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Consente all\'app di verificare se un filtro di intent è stato verificato o meno."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"collegamento a uno strumento di verifica dei filtri di intent"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Consente al proprietario di effettuare richieste relative agli strumenti di verifica dei filtri di intent. Non dovrebbe mai essere necessario per applicazioni normali."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accesso a fornitori di contenuti esterni"</string>
@@ -1405,7 +1426,7 @@
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Tocca per disattivare il debug USB."</string>
     <string name="select_input_method" msgid="8547250819326693584">"Cambia tastiera"</string>
-    <string name="configure_input_methods" msgid="4769971288371946846">"Scegli tastiere"</string>
+    <string name="configure_input_methods" msgid="4769971288371946846">"Scegli tastiera"</string>
     <string name="show_ime" msgid="9157568568695230830">"Mostra metodo immissione"</string>
     <string name="hardware" msgid="7517821086888990278">"Hardware"</string>
     <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"Seleziona layout tastiera"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Riduci giorno"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumenta anno"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Riduci anno"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mese precedente"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mese successivo"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annulla"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Canc"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Seleziona i minuti"</string>
     <string name="select_day" msgid="7774759604701773332">"Seleziona mese e giorno"</string>
     <string name="select_year" msgid="7952052866994196170">"Seleziona anno"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Elemento selezionato: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminato"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> lavoro"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Per sbloccare questa schermata, tocca e tieni premute contemporaneamente le opzioni Indietro e Panoramica."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Richiedi il PIN prima di sbloccare"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Richiedi sequenza di sblocco prima di sbloccare"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Richiedi password prima di sbloccare"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Per aumentare la durata della batteria, la funzione di risparmio energetico riduce le prestazioni del dispositivo e limita vibrazione, servizi di localizzazione e la maggior parte dei dati in background. App di email, messaggi e altre app che si basano sulla sincronizzazione potrebbero essere aggiornate soltanto all\'apertura.\n\nLa funzione di risparmio energetico viene disattivata automaticamente quando il dispositivo è in carica."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Fino al termine del periodo di inattività previsto per le <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Fino al termine del periodo di inattività"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 54367fe..f1932d3 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -126,9 +126,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"מודעת באנר נודדת כבויה"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"מחפש שירות"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"‏שיחות ב-Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"כבוי"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"‏Wi-Fi מועדף"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"סלולרי מועדף"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"‏Wi-Fi בלבד"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ללא העברה"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> כעבור <xliff:g id="TIME_DELAY">{2}</xliff:g> שניות"</string>
@@ -587,6 +593,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"השבת את נורית מצב השידור כשהמצלמה בשימוש"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"מתיר לאפליקציית מערכת המותקן מראש להשבית את השימוש של המצלמה בנורית המצב."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"התר לאפליקציית מערכת שהותקנה מראש לשלוח את אירועי המערכת של שירות המצלמה."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"השבת טאבלט לצמיתות"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"השבתה של הטלוויזיה לצמיתות"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"השבת טלפון לצמיתות"</string>
@@ -635,6 +642,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"‏הפעלה ישירה של הגדרת CDMA בטלוויזיה"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"‏הפעל ישירות הגדרה של טלפון CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"‏מאפשר לאפליקציה להפעיל הקצאת CDMA. אפליקציות זדוניות עלולות להפעיל הקצאת CDMA ללא צורך."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"‏התחל הגדרה של כרטיס SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"‏מאפשר לאפליקציה לטפל בבקשות הפעלה של SIM. האפליקציה עשויה לבצע הפעלה באופן ישיר או להאציל לאפליקציה אחרת."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"שלוט בהתראות על עדכון מיקום"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"מאפשר לאפליקציה לאפשר/להשבית התראות לגבי עדכוני מיקום מהרדיו. לא מיועד לשימוש על ידי אפליקציות רגילות."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"גישה למאפייני כניסה"</string>
@@ -760,8 +769,8 @@
     <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"אין אפשרות לעבד. נסה שוב."</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"החומרה לא זמינה."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"לא ניתן לאחסן טביעת אצבע. הסר טביעת אצבע קיימת."</string>
-    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף זמן קצוב לתפוגה של טביעת אצבע. נסה שוב."</string>
-    <string name="fingerprint_error_vendor" msgid="3175724710791609491">"חלף זמן קצוב לתפוגה של טביעת אצבע. נסה שוב."</string>
+    <string name="fingerprint_error_timeout" msgid="3927186043737732875">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
+    <string name="fingerprint_error_vendor" msgid="3175724710791609491">"חלף הזמן הקצוב לטביעת אצבע. נסה שוב."</string>
   <string-array name="fingerprint_error_vendor">
     <item msgid="5804600450373644614">"הודעת שגיאה ספציפית לספק."</item>
   </string-array>
@@ -841,6 +850,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"‏הרשאה זו מאפשרת לאפליקציה להסיר אישורי DRM. באפליקציות רגילות אף פעם לא אמור להיות בה צורך."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"איגוד לשירות העברת הודעות של ספק"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"מאפשרת לבעלים לאגד לממשק ברמה העליונה של שירות העברת הודעות של ספק. לעולם לא אמורה להיות נחוצה עבור אפליקציות רגילות."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"אינטראקציה עם שירות אינטראקציה קולית"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"מאפשר לבעלים לקיים אינטראקציה עם השירות הפעיל הנוכחי של אינטראקציה קולית. לא אמורה להיות נחוצה לאפליקציות רגילות."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"הגדר כללי סיסמה"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"‏קביעת האורך הנדרש והתווים המותרים בסיסמאות ובקודי PIN של מסך הנעילה."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"עקוב אחר ניסיונות לביטול נעילת מסך"</string>
@@ -1138,6 +1149,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"מאפשר לאפליקציה לאמת שחבילה ניתנת להתקנה."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"הכפפה למאמת חבילה"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה לאפליקציות רגילים."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"אימות של מסנן כוונה"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"מאפשר לאפליקציה לבדוק אם מסנן כוונה אומת או לא."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"הכפפה אל מאמת של מסנן כוונה"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"מאפשר למשתמש להגיש בקשות של מאמתי סינון כוונה. לעולם לא אמור להיות נחוץ לאפליקציות רגילות."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"‏מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"גישה לספקי תוכן באופן חיצוני"</string>
@@ -1577,6 +1592,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"הפחת יום"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"הוסף שנה"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"הפחת שנה"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"החודש הקודם"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"החודש הבא"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ביטול"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"מחק"</string>
@@ -1831,7 +1848,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"בחר דקות"</string>
     <string name="select_day" msgid="7774759604701773332">"בחר חודש ויום"</string>
     <string name="select_year" msgid="7952052866994196170">"בחר שנה"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> נבחר"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> נמחק"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"עבודה <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"כדי לבטל את הקפאת המסך הזה, גע בו-זמנית נגיעה ממושכת ב\'הקודם\' ו\'סקירה\'."</string>
@@ -1842,6 +1858,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"בקש קוד אימות לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"בקש קו ביטול נעילה לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"בקש סיסמה לפני ביטול הצמדה"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"כדי לעזור בשיפור חיי הסוללה, תכונת החיסכון בסוללה מצמצמת את פעולות המכשיר ומגבילה רטט, שירותי מיקום ואת רוב נתוני הרקע. אימייל, העברת הודעות ואפליקציות אחרות המסתמכות על סנכרון עשויות שלא להתעדכן, אלא אם תפתח אותן.\n\nתכונת החיסכון בסוללה מושבתת אוטומטית כשהמכשיר בטעינה."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"עד לסיום ההשבתה בשעה <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"עד לסיום זמן ההשבתה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e4ef4be..979129b2 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"ローミングバナーOFF"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"サービスを検索中"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi通話"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:転送できません"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g> (<xliff:g id="TIME_DELAY">{2}</xliff:g>秒後)"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"カメラの使用中に通信インジケータLEDを無効にする"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"カメラ使用インジケータLEDを無効にすることをプレインストールされているシステムアプリに許可します。"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"カメラサービスにシステムイベントを送信することをプレインストールされているシステムアプリに許可します。"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"タブレットを完全に無効化"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"テレビを完全に無効化"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"端末を永続的に無効にする"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMAテレビのセットアップを直接開始"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA携帯電話のセットアップを直接開始"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMAプロビジョニングの開始をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、不要なCDMAプロビジョニングが開始される恐れがあります。"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"位置情報の更新通知"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"無線からの現在地情報のアップデート通知を有効/無効にすることをアプリに許可します。通常のアプリでは使用しません。"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"チェックインプロパティへのアクセス"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM証明書の削除をアプリに許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"携帯通信会社のSMSサービスへのバインド"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"携帯通信会社のSMSサービスのトップレベルインターフェースにバインドすることを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"音声対話サービスとの通信"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"現在有効になっている音声対話サービスとの通信を所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"パスワードルールの設定"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"画面ロックのパスワードとPINの長さと使用できる文字を制御します。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"画面ロック解除試行の監視"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"パッケージがインストール可能かどうか確認することをアプリに許可します。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"パッケージベリファイアにバインド"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"インテントフィルタの検証"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"インテントフィルタが検証されているかどうかを確認することをアプリに許可します。"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"インテントフィルタベリファイアにバインド"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"インテントフィルタベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"コンテンツプロバイダへの外部アクセス"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"1日戻します"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"1年進めます"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"1年戻します"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"前月"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"翌月"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"キャンセル"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"削除"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"分を選択"</string>
     <string name="select_day" msgid="7774759604701773332">"月と日を選択"</string>
     <string name="select_year" msgid="7952052866994196170">"年を選択"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>を選択しました"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g>を削除しました"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"仕事の<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"この画面の固定を解除するには[戻る]と[最近]を同時に押し続けます。"</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"オフライン再生を解除する前にPINの入力を求める"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"オフライン再生を解除する前にパスワードの入力を求める"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使用するその他のアプリは、起動しても更新されないことがあります。\n\nバッテリーセーバーは端末の充電中は自動的にOFFになります。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>にダウンタイムが終わるまで"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ダウンタイム終了まで"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 8f9e8cf..50da83f 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"როუმინგის ბანერი გამორთულია"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"სერვისის ძიება"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"დარეკვა Wi-Fi-ს მეშვეობით"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: არ არის გადამისამართებული"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> წამის შემდეგ"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"კამერის გამოყენებისას გადამცემი ინდიკატორის LED გათიშვა"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ნებას რთავს წინასწარ დაყენებული სისტემის აპლიკაციას, გამორთოს კამერის გამოყენების ინდიკატორი LED."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"საშუალებას აძლევს წინასწარ დაყენებულ სისტემის აპლიკაციებს გააგზავნონ კამერის მომსახურების სისტემური მოვლენები."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"მუდმივად გამორთული ტაბლეტი"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ტელევიზორის მუდმივად გამორთვა"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ტელეფონის სამუდამოდ დეაქტივაცია"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"პირდაპირ დაიწყოს CDMA ტელევიზორის დაყენება"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA ტელეფონის დაყენების პირდაპირ დაწყება"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"აპს შეეძლება, დაიწყოს CDMA უზრუნველყოფა. მავნე აპებმა შეიძლება ზედმეტად, საჭიროების გარეშე დაიწყონ CDMA უზრუნველყოფა."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"მდებარეობის განახლების შეტყობინებების კონტროლი"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"აპს შეეძლება მდებარეობის განახლების შესახებ რადიო შეტყობინებების აქტივაცია/დეაქტივაცია. ჩვეულებრივი აპები ამ ფუნქციას არ იყენებენ."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"სარეგისტრაციო პარამეტრებზე წვდომა"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"საშუალებას აძლევს აპლიკაციას ამოშალოს DRM სერtიფიკატები. ეს წესით ჩვეულებრივ აპებს არ უნდა დაჭირდეს."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"აკავშირებს შეტყობინების გაცვლის მომსახურებას"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"საშუალებას აძლევს მფლობელს შექმნას შეტყობინების გაცვლის მომსახურების უმახლესი დონის ინტერფეისი. არასდროს იქნება საჭირო ნორმალური აპლიკაციებისათვის."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"იურთიერთქმედოს ხმოვანი ურთიერთქმედების მომსახურებასთან"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"საშუალებას აძლევს მფლობელს იურთიერთქმედოს ამჟამად აქტიური ხმოვან ურთიერთქმედების მომსახურებასთან. არასდროს არ უნდა იყოს საჭირო ნორმალურ აპლიკაციებისათვის."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"პაროლის წესების დაყენება"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"აკონტროლეთ ეკრანის ბლოკირების პაროლებისა და PIN-ების სიმბოლოების სიგრძე."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ეკრანის განბლოკვის მცდელობების გაკონტროლება"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"აპს შეუძლია დაადასტუროს პაკეტის დაყანების შესაძლებლობა."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"პაკეტების ვერიფიკატორებთან დაკავშირება"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"მფლობელს შეეძლება პაკეტის ვერიფიკატორების მოთხოვნა. არასდროს გამოიყენება ჩვეულებრივ აპებში."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"სამიზნე ფილტრის დამოწმება"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"საშუალებას აძლევს აპლიკაციას შეამოწმოს დამოწმებულია თუ არა სამიზნე ფილტრი."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"სამიზნე ფილტრის დამოწმებაზე მიბმა"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"საშუალებას აძლევს მფლობელს მოითხოვოს სამიზნე ფილტრის დამოწმება. არასოდეს არის საჭირო ნორმალური აპლიკაციისას."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"სერიულ პორტებზე წვდომა"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"მფლობელს შეეძლება სერიულ პორტებზე წვდომა სერიული მენეჯერის  API-ის გამოყენებით."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"კონტენტის მომწოდებლებთან გარედან წვდომა"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"დღის მოკლება"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"წლის მომატება"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"წლის მოკლება"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"წინა თვე"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"მომდევნო თვე"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"გაუქმება"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"წაშლა"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"აირჩიეთ წუთები"</string>
     <string name="select_day" msgid="7774759604701773332">"აირჩიეთ თვე და რიცხვი"</string>
     <string name="select_year" msgid="7952052866994196170">"აირჩიეთ წელი"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"არჩეულია <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> წაიშალა"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"სამსახური <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"მიმაგრების გასაუქმებლად ერთდროულად შეეხეთ და არ აუშვათ ღილაკებს „უკან“ და „მიმოხილვა“."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ფიქსაციის მოხსნამდე PIN-ის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ელემენტის მოქმედების ვადის გაუმჯობესებისათვის, ელემენტის დამზოგი ამცირებს თქვენი მოწყობილობის შესრულებას და ზღუდავს ვიბრაციას, ადგილმდებარეობის მომსახურებებს და ძირითად ფონურ მონაცემებს. ელ-ფოსტა, შეტყობინებები და სხვა სინქრონიზაციაზე დაყრდნობილი აპლიკაციების განახლება არ მოხდება მათ გახსნეამდე. \n\n ელემენტის დამზოგველი ავტომატურად გამოირთვება, როდესაც თქვენს მოწყობილობას დამტენთან შეაერთებთ."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"დანამ თქვენი კავშირგარეშე დრო დასრულდებოდეს <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ზე"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"სანამ ავარიული პაუზა დასრულდებოდეს"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 45f91b5..e2c98db 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Роуминг баннері өшірулі"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Қызметті іздеу"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi қоңыраулары"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Басқа нөмірге бағытталмады"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>  <xliff:g id="TIME_DELAY">{2}</xliff:g> секундтан кейін"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"камера қолданыста болғанда жарық диодты шамы бар көрсеткішті өшіру"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Алдын ала орнатылған жүйе қолданбасына камераның жарық диодты көрсеткішті қолдануын өшіру мүмкіндігін береді."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Алдын ала орнатылған жүйе қолданбасына камера қызметі жүйесінің оқиғаларын жіберуге рұқсат береді."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"планшетті мүлдем өшіру"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ТД біржола өшіру"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"телефонды мүлдем өшіру"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA ТД параметрлерін орнатуды тікелей бастау"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"тікелей CDMA телефон орнатуларын бастау"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Қолданбаға CDMA дайындауды бастауға рұқсат береді. Зиянкес қолданбалар CDMA дайындауды қажет емес кезде бастауы мүмкін."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"аймақ жаңарту хабарларын басқару"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Қолданбаға радиодан алынатын орынды жаңарту туралы хабарландыруларды қосуға/өшіруге рұқсат береді. Қалыпты қолданбалардың пайдалануына арналмаған."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"тіркелу деректеріне кіру"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Қолданбаға DRM сертификаттарын жоюға рұқсат етеді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"оператордың хабар алмасу қызметіне байластыру"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Иесіне оператордың хабар алмасу қызметінің жоғарғы деңгейлі интерфейсіне байластыруға рұқсат етеді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"Дауыстық интерактивті қызметпен өзара әрекеттесу"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Ұстаушыға ағымда белсенді дауыстық интерактивті қызметпен өзара әрекеттесу мүмкіндігін береді. Қалыпты қолданбалар үшін ешқашан қажет болмауы тиіс."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Кілтсөз ережелерін тағайындау"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Экран бекітпесінің құпия сөздерінің және PIN кодтарының ұзындығын және оларда рұқсат етілген таңбаларды басқару."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Экранды ашу әркеттерін бақылау"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Қолданбаға буманы орнатуға болатынын тексеруге рұқсат береді."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"жинақ растау қызметіне байланыстыру"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Пайдаланушыға бума верификаторларының сұрауларын жасауға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"интент-сүзгіні тексеру"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Қолданбаға интент-сүзгі тексерілген не тексерілмегенін анықтау мүмкіндігін береді."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"интент-сүзгі верификаторына байланыстыру"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Пайдаланушыға интент-сүзгі верификаторларының сұрауларын жасауға рұқсат береді. Қалыпты қолданбалар үшін ешқашан қажет болмайды."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"сериялық портқа кіру"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Пайдаланушыға Сериялық Менеджер қолданба бағдарламалау интерфейсін қолданып, сериялық порттарға кіру мүмкіндігін ұсынады."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"мазмұн жабдықтаушыларға сырттан қатынасу"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Күн азайту"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Жыл арттыру"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Жыл азайту"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Алдыңғы ай"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Келесі ай"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Өшіру"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жою"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Минут таңдау"</string>
     <string name="select_day" msgid="7774759604701773332">"Ай мен күнді таңдау"</string>
     <string name="select_year" msgid="7952052866994196170">"Жыл таңдау"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> таңдалды"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> жойылды"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жұмыс <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Осы экранды босату үшін «Кері» және «Шолу» пәрмендерін бір уақытта түртіп, ұстап тұрыңыз."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Босату алдында PIN кодын сұрау"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Босату алдында бекітпесін ашу өрнегін сұрау"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Босату алдында құпия сөзді сұрау"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Батареяның қызмет көрсету мерзімін жақсарту үшін батарея үнемдегіш құрылғының өнімділігін төмендетеді және дірілді, орынды анықтау қызметтерін және фондық деректердің көпшілігін шектейді. Электрондық пошта, хабар алмасу және синхрондауға негізделген басқа қолданбалар ашқанша жаңартылмауы мүмкін.\n\nБатарея үнемдегіш құрылғы зарядталып жатқанда автоматты түрде өшеді."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> уақытында әрекетсіздік аяқталғанша"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Бос тұру уақыты аяқталғанша"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 9ccc1ab..9eddb21 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"បិទ​បដា​រ៉ូមីង"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"​ស្វែង​រក​សេវាកម្ម"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"ការហៅតាម Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"បិទ"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"គួរប្រើ Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"គួរប្រើប្រព័ន្ធទូរស័ព្ទ"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi តែប៉ុណ្ណោះ"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> ៖ មិន​បាន​បញ្ជូន​បន្ត"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> បន្ទាប់​ពី <xliff:g id="TIME_DELAY">{2}</xliff:g> វិនាទី"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យ​កម្មវិធី​ថត​រូប និង​វីដេអូ​ដោយ​ប្រើ​ម៉ាស៊ីន​ថត។ វា​ឲ្យ​កម្មវិធី​​ប្រើ​ម៉ាស៊ីន​ថត​នៅ​ពេល​​ណាមួយ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"បិទ​​ពន្លឺ​បង្ហាញ​ការ​បញ្ជូន​​ពេល​ម៉ាស៊ីន​ថត​កំពុង​ប្រើ"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ឲ្យ​កម្មវិធី​ប្រព័ន្ធ​ដែល​បាន​ដំឡើង​រួច​បិទ​​ LED បង្ហាញ​ការ​ប្រើ​ម៉ាស៊ីន​ថត។"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"អនុញ្ញតឲ្យកម្មវិធីប្រព័ន្ធដែលបានដំឡើងជាមុនផ្ញើព្រឹត្តិការណ៍ប្រព័ន្ធសេវាកាមេរ៉ា។"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"បិទ​កុំព្យូទ័រ​បន្ទះ​ជា​អចិន្ត្រៃយ៍"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"បិទដំណើរការទូរទស្សន៍ជាអចិន្ត្រៃយ៍"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"បិទ​ទូរស័ព្ទ​ជា​អចិន្ត្រៃយ៍"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"ចាប់ផ្តើមកំណត់ទូរទស្សន៍ CDMA ដោយផ្ទាល់"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ចាប់ផ្ដើម​រៀបចំ​កុំព្យូទ័រ​បន្ទះ CDMA ដោយ​ផ្ទាល់"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"ឲ្យ​កម្មវិធី​ចាប់ផ្ដើម​ការ​ផ្ដល់ CDMA ។ កម្មវិធី​ព្យាបាទ​អាច​មិន​ចាំបាច់​ចាប់ផ្ដើម​ការ​ផ្ដល់ CDMA ។"</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"ចាប់ផ្តើមការដំឡើងស៊ីមកាត"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"អនុញ្ញាតឲ្យកម្មវិធីគ្រប់គ្រងសំណើធ្វើឲ្យសកម្មស៊ីមកាត។ កម្មវិធីនេះអាចដំណើរការធ្វើឲ្យសកម្មដោយផ្ទាល់ ឬក៏ផ្ទេរសិទ្ធិទៅឲ្យកម្មវិធីមួយផ្សេងទៀត។"</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ពិនិត្យ​​ការ​ជូន​ដំណឹង​បច្ចុប្បន្ន​ភាព​ទីតាំង"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ឲ្យ​កម្មវិធី​បិទ/បើក​ការ​ជូន​ដំណឹង​បច្ចុប្បន្នភាព​ទីតាំង​ពី​វិទ្យុ។ មិន​សម្រាប់​ប្រើ​ដោយ​កម្មវិធី​ធម្មតា​ទេ។។"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"ចូល​ដំណើរការ​លក្ខណៈ​សម្បត្តិ​ពិនិត្យ​មើល"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"អនុញ្ញាត​ឲ្យ​​កម្មវិធី​លុប​ចេញ​វិញ្ញាបនបត្រ DRM ​។ គួរ​តែ​មិន​ត្រូវការ​សម្រាប់​កម្មវិធី​ធម្មតា​។"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ភ្ជាប់ទៅសេវាកម្មសារអ្នកផ្តល់សេវាកម្មទូរស័ព្ទ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"អនុញ្ញាតឲ្យអ្នកប្រើភ្ជាប់ទៅអ៊ីនធឺហ្វេសកម្រិតខ្ពស់នៃសេវាកម្មសារអ្នកផ្តល់សេវាកម្មទូរស័ព្ទ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ធ្វើអន្តរកម្មជាមួយសេវាកម្មអន្តរកម្មសម្លេងដែលសកម្ម"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"អនុញ្ញាតឲ្យម្ចាស់ធ្វើអន្តរកម្មជាមួយសេវាកម្មអន្តរកម្មសម្លេងដែលសកម្មថ្មីៗនេះ។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"កំណត់​ក្បួន​ពាក្យ​សម្ងាត់"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"គ្រប់គ្រងប្រវែង និងតួអក្សរដែលអនុញ្ញាតឲ្យប្រើក្នុងពាក្យសម្ងាត់ និងលេខសម្ងាត់ចាក់សោអេក្រង់។"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ពិនិត្យ​ការ​ព្យាយាម​ដោះ​សោ​អេក្រង់"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ឲ្យ​កម្មវិធី​ផ្ទៀងផ្ទាត់​កញ្ចប់​ដែល​អាច​ដំឡើង​បាន។"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ចង​ទៅ​កម្មវិធី​ផ្ទៀងផ្ទាត់​កញ្ចប់"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ឲ្យ​ម្ចាស់​ស្នើ​កម្មវិធី​ផ្ទៀងផ្ទាត់​កញ្ចប់។ មិន​គួរ​ចាំបាច់​សម្រាប់​កម្មវិធី​ធម្មតា​ទេ។"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ផ្ទៀងផ្ទាត់តម្រងចេតនា"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"អនុញ្ញាតឲ្យកម្មវិធីពិនិត្យមើលថាតើតម្រងចេតនាត្រូវបានផ្ទៀងផ្ទាត់ហើយឬនៅ។"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ចងភ្ជាប់ទៅកម្មវិធីផ្ទៀងផ្ទាត់តម្រងចេតនា"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"អនុញ្ញាតឲ្យអ្នកគ្រប់គ្រងធ្វើការស្នើកម្មវិធីផ្ទៀងផ្ទាត់តម្រងចេតនា។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតានោះទេ។"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"ចូល​ដំណើរការ​ច្រក​ស៊េរី"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"អនុញ្ញាត​ឱ្យ​ចូល​ដំណើរ​ការ​ទៅ​កាន់​ច្រក​សៀរៀល​ដោយ​ប្រើ SerialManager API ។"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ចូល​ដំណើរការ​ក្រុមហ៊ុន​ផ្ដល់​មាតិកា​ខាង​ក្រៅ"</string>
@@ -1563,6 +1578,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"បន្ថយ​ថ្ងៃ"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"បង្កើន​​ឆ្នាំ"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"បន្ថយ​ឆ្នាំ"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ខែមុន"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"ខែក្រោយ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"បោះ​បង់​"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"លុប"</string>
@@ -1815,7 +1832,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"ជ្រើស​នាទី"</string>
     <string name="select_day" msgid="7774759604701773332">"ជ្រើស​ខែ និង​ថ្ងៃ"</string>
     <string name="select_year" msgid="7952052866994196170">"ជ្រើស​ឆ្នាំ"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"បាន​ជ្រើស <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"បាន​លុប <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"កន្លែង​ធ្វើការ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ដើម្បី​មិន​ភ្ជាប់​អេក្រង់​នេះ ប៉ះ ហើយ​សង្កត់​ថយក្រោយ និង​ទិដ្ឋភាព​នៅ​ពេល​តែ​មួយ។"</string>
@@ -1826,6 +1842,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"សួរ​រក​កូដ PIN មុន​ពេល​ផ្ដាច់"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"សួរ​រក​លំនាំ​ដោះ​សោ​មុន​ពេល​ផ្ដាច់"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"សួរ​រក​ពាក្យ​សម្ងាត់​មុន​ពេល​ផ្ដាច់"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ដើម្បីជួយឲ្យថាមពលថ្មប្រសើរឡើង កម្មវិធីសន្សំសំចៃថាមពលថ្មកាត់បន្ថយប្រតិបត្តិការឧបករណ៍របស់អ្នក និងកម្រិតភាពញ័រ សេវាកម្មទីតាំង និងទិន្នន័យផ្ទៃខាងក្រោយស្ទើរតែទាំងអស់។ ការផ្ញើសារអ៊ីម៉ែល និងកម្មវិធីផ្សេងទៀតដែលពឹងផ្អែកលើការធ្វើសមកាលកម្មអាចនឹងមិនធ្វើបច្ចុប្បន្នភាពទេ លុះត្រាតែអ្នកបើកពួកវា។\n\nកម្មវិធីសន្សំសំចៃបិទដោយស្វ័យប្រវត្តិ នៅពេលដែលឧបករណ៍របស់អ្នកកំពុងសាកថ្ម។"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"រហូត​ដល់ម៉ោង​សម្រាក ឬរវល់​របស់​អ្នក​បញ្ចប់​នៅ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"រហូត​ដល់​ម៉ោង​រាប់​ថយក្រោយ​ចប់"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index 9c10119..f9fbd34 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"ರೋಮಿಂಗ್ ಬ್ಯಾನರ್ ಆಫ್ ಆಗಿದೆ"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"ಸೇವೆ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ಆಫ್"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ವೈ-ಫೈಗೆ ಆದ್ಯತೆ ನೀಡಲಾಗಿದೆ"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"ಸೆಲ್ಯುಲಾರ್‌ಗೆ ಆದ್ಯತೆ ನೀಡಲಾಗಿದೆ"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"ವೈ-ಫೈ ಮಾತ್ರ"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ಫಾರ್ವರ್ಡ್ ಮಾಡಲಾಗಿಲ್ಲ"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> ಸೆಕೆಂಡುಗಳ ನಂತರ <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ಕ್ಯಾಮರಾ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಪ್ರಸಾರ ಸೂಚಕ LED ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ಕ್ಯಾಮರಾ ಬಳಕೆ ಸೂಚಕ LED ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಪೂರ್ವ-ಸ್ಥಾಪಿತ ಸಿಸ್ಟಂ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"ಕ್ಯಾಮರಾ ಸೇವೆ ಸಿಸ್ಟಂ ಈವೆಂಟ್‌ಗಳನ್ನು ಕಳುಹಿಸಲು ಪೂರ್ವ-ಸ್ಥಾಪಿತ ಸಿಸ್ಟಂ ಅಪ್ಲಿಕೇಶನ್‌ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ಶಾಶ್ವತವಾಗಿ ಟ್ಯಾಬ್ಲೆಟ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ಟಿವಿಯನ್ನು ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ಶಾಶ್ವತವಾಗಿ ಫೋನ್ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA ಟಿವಿ ಸೆಟಪ್ ಅನ್ನು ನೇರವಾಗಿ ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA ಫೋನ್ ಸೆಟಪ್ ಅನ್ನು ನೇರವಾಗಿ ಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMA ಒದಗಿಸುವಿಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಅನಗತ್ಯವಾಗಿ CDMA ಒದಗಿಸುವಿಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಬಹುದು."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"ಸಿಮ್‌ ಕಾರ್ಡ್‌ ಸೆಟಪ್‌ ಪ್ರಾರಂಭಿಸಿ"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"ಸಿಮ್ ಸಕ್ರಿಯಗೊಳಿಸುವ ವಿನಂತಿಗಳನ್ನು ನಿರ್ವಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಅಪ್ಲಿಕೇಶನ್ ನೇರವಾಗಿ  ಕಾರ್ಯ ನಿರ್ವಹಿಸಬಹುದು ಅಥವಾ ಮತ್ತೊಂದು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಪ್ರತಿನಿಧಿಸಬಹುದು."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ಸ್ಥಾನ ನವೀಕರಣದ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ರೇಡಿಯೊದಿಂದ ಸ್ಥಳ ನವೀಕರಣ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು/ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಬಳಕೆಗಲ್ಲ."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"ಚೆಕ್ಇನ್ ಗುಣಲಕ್ಷಣಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM ಪ್ರಮಾಣಪತ್ರಗಳನ್ನು ತೆಗೆದುಹಾಕಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ವಾಹಕ ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ ಸೇವೆಗೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ವಾಹಕ ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ ಸೇವೆಯ ಮೇಲ್ಮಟ್ಟದ ಇಂಟರ್ಫೇಸ್‌ಗೆ ಪ್ರತಿಬಂಧಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗಾಗಿ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ಧ್ವನಿ ಪರಸ್ಪರ ಸೇವೆಯ ಜೊತೆಗೆ ಸಂವಾದ ನಡೆಸಿ"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"ಪ್ರಸ್ತುತ ಸಕ್ರಿಯವಾಗಿರುವ ಧ್ವನಿ ಪರಸ್ಪರ ಸೇವೆಯ ಜೊತೆಗೆ ಸಂವಾದ ಮಾಡಲು ಮಾಲೀಕರಿಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ಪಾಸ್‌ವರ್ಡ್ ನಿಮಯಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ಪರದೆ ಲಾಕ್‌ನಲ್ಲಿನ ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಪಿನ್‌ಗಳ ಅನುಮತಿಸಲಾದ ಅಕ್ಷರಗಳ ಪ್ರಮಾಣವನ್ನು ನಿಯಂತ್ರಿಸಿ."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ಪರದೆಯ-ಅನ್‌ಲಾಕ್ ಪ್ರಯತ್ನಗಳನ್ನು ಮಾನಿಟರ್ ಮಾಡಿ"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ಪ್ಯಾಕೇಜ್‌‌‌ ಅನ್ನು ಸ್ಥಾಪಿಸಬಹುದಾದ ಪರಿಶೀಲನೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್‌‌ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ಪ್ಯಾಕೇಜ್ ಪರಿಶೀಲಕಕ್ಕೆ ಪ್ರತಿಬಂಧಿಸಿ"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ಪ್ಯಾಕೇಜ್‌ ಪರಿಶೀಲನಾಗಾರರ ವಿನಂತಿಗಳನ್ನು ಮಾಡಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ಉದ್ದೇಶಿತ ಫಿಲ್ಟರ್ ಪರಿಶೀಲಿಸಿ"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ಇಂಟರ್ನೆಟ್ ಫಿಲ್ಟರ್ ಅನ್ನು ಪರಿಶೀಲಿಸಲಾಗಿದೆಯೇ ಅಥವಾ ಇಲ್ಲವೆ ಎಂಬುದನ್ನು ಪರೀಕ್ಷಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ಉದ್ದೇಶಿತ ಫಿಲ್ಟರ್ ಪರಿಶೀಲಕವನ್ನು ಪ್ರತಿಬಂಧಿಸಿ"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ಉದ್ದೇಶಿತ ಫಿಲ್ಟರ್ ಪರಿಶೀಲನಾಗಾರರ ವಿನಂತಿಗಳನ್ನು ಮಾಡಲು ಹೊಂದಿರುವವರಿಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಸಾಮಾನ್ಯ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"ಸರಣಿ ಪೋರ್ಟ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API ಬಳಸಿಕೊಂಡು ಸರಣಿ ಪೋರ್ಟ್‌ಗಳಿಗೆ ಪ್ರವೇಶ ಪಡೆಯಲು ಹೊಂದಿರುವವರಿಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ವಿಷಯ ಪೂರೈಕೆದಾರರನ್ನು ಬಾಹ್ಯ ರೀತಿಯಲ್ಲಿ ಪ್ರವೇಶಿಸಿ"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ದಿನವನ್ನು ಕಡಿಮೆಮಾಡಿ"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ವರ್ಷವನ್ನು ಹೆಚ್ಚಿಸಿ"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ವರ್ಷವನ್ನು ಕಡಿಮೆಮಾಡಿ"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ಹಿಂದಿನ ತಿಂಗಳು"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"ಮುಂದಿನ ತಿಂಗಳು"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ರದ್ದುಮಾಡು"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ಅಳಿಸು"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"ನಿಮಿಷಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="select_day" msgid="7774759604701773332">"ತಿಂಗಳು ಮತ್ತು ದಿನವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="select_year" msgid="7952052866994196170">"ವರ್ಷವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ಆಯ್ಕೆ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ಅಳಿಸಲಾಗಿದೆ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ಕೆಲಸ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ಈ ಪರದೆಯನ್ನು ಅನ್‌ಪಿನ್ ಮಾಡಲು, ‘ಹಿಂದೆ’ ಮತ್ತು ‘ಸಮಗ್ರ ನೋಟ’ವನ್ನು ಏಕಕಾಲದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ಅನ್‌ಪಿನ್ ಮಾಡುವುದಕ್ಕೂ ಮೊದಲು ಪಿನ್‌ ಕೇಳಿ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ಅನ್‌ಪಿನ್ ಮಾಡುವುದಕ್ಕೂ ಮೊದಲು ಅನ್‌ಲಾಕ್ ನಮೂನೆಯನ್ನು ಕೇಳಿ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ಅನ್‌ಪಿನ್ ಮಾಡುವುದಕ್ಕೂ ಮೊದಲು ಪಾಸ್‌ವರ್ಡ್ ಕೇಳಿ"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ನಿಮ್ಮ ಬ್ಯಾಟರಿಯ ಬಾಳಿಕೆಯನ್ನು ಸುಧಾರಿಸಲು ಸಹಾಯ ಮಾಡಲು, ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ನಿಮ್ಮ ಸಾಧನದ ಕಾರ್ಯಕ್ಷಮತೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ ಮತ್ತು ವೈಬ್ರೇಷನ್, ಸ್ಥಳ ಸೇವೆಗಳು ಹಾಗೂ ಹೆಚ್ಚಿನ ಹಿನ್ನೆಲೆ ಡೇಟಾವನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ. ಸಿಂಕ್ ಮಾಡುವುದನ್ನು ಅವಲಂಬಿಸಿರುವ ಇಮೇಲ್, ಸಂದೇಶ ಕಳುಹಿಸುವಿಕೆ, ಮತ್ತು ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ನೀವು ತೆರೆಯದ ಹೊರತು ನವೀಕರಣಗೊಳ್ಳುವುದಿಲ್ಲ.\n\nನಿಮ್ಮ ಸಾಧನವು ಚಾರ್ಜ್ ಆಗುತ್ತಿರುವ ಸಮಯದಲ್ಲಿ ಬ್ಯಾಟರಿ ಉಳಿಕೆಯು ಆಫ್ ಆಗುತ್ತದೆ."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"ನಿಮ್ಮ ಅಲಭ್ಯತೆ ಕೊನೆಗೊಳ್ಳುವವರೆಗೆ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ನಿಮ್ಮ ಸ್ಥಗಿತಕಾಲ ಕೊನೆಗೊಳ್ಳುವವರೆಗೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 6da084e..0061f63 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"로밍 배너 사용 안함"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"서비스 검색 중"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi 통화"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: 착신전환 안됨"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g><xliff:g id="TIME_DELAY">{2}</xliff:g>초 후"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"카메라를 사용할 때 전송 표시 LED 사용 중지"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"사전 설치된 시스템 애플리케이션에서 카메라 사용 표시 LED를 사용 중지하도록 허용합니다."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"사전 설치된 시스템 애플리케이션에서 카메라 서비스 시스템 이벤트를 전송하도록 허용합니다."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"영구적으로 태블릿 사용 안함"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"TV를 영구적으로 사용 중지"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"휴대전화를 영구적으로 사용 중지"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA TV 설정 바로 시작"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"직접 CDMA 전화 설정 시작"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"앱이 CDMA 프로비저닝을 시작할 수 있도록 허용합니다. 이 경우 악성 앱이 불필요하게 CDMA 프로비저닝을 시작할 수 있습니다."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"위치 업데이트 알림 제어"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"앱이 무선의 위치 업데이트 알림을 사용하거나 사용하지 않도록 허용합니다. 일반 앱에서는 사용하지 않습니다."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"체크인 속성 액세스"</string>
@@ -747,15 +762,15 @@
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"사용할 지문 템플릿의 추가 및 삭제 메소드를 앱에서 실행하도록 허용합니다."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"지문 하드웨어 사용"</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"앱에서 지문 하드웨어를 인증에 사용하도록 허용합니다."</string>
-    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"지문이 일부만 감지되었습니다. 다시 시도해 주세요."</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"지문을 처리할 수 없습니다. 다시 시도해 주세요."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"지문 센서가 더럽습니다. 깨끗이 닦고 다시 시도하세요."</string>
+    <string name="fingerprint_acquired_partial" msgid="735082772341716043">"지문이 일부만 인식되었습니다. 다시 시도해 주세요."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"지문을 인식할 수 없습니다. 다시 시도해 주세요."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"지문 센서를 깨끗이 닦고 다시 시도하세요."</string>
     <string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"손가락을 너무 빨리 움직였습니다. 다시 시도해 주세요."</string>
     <string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"손가락을 너무 느리게 움직였습니다. 다시 시도해 주세요."</string>
   <string-array name="fingerprint_acquired_vendor">
     <item msgid="2892952818207766996">"공급업체별 획득 오류 메시지 0"</item>
   </string-array>
-    <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"처리할 수 없습니다. 다시 시도하세요."</string>
+    <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"인식할 수 없습니다. 다시 시도하세요."</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"하드웨어를 사용할 수 없습니다."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"지문을 저장할 수 없습니다. 기존 지문을 삭제하세요."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"지문 인식 시간이 초과되었습니다. 다시 시도하세요."</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"애플리케이션이 DRM 인증서를 삭제하도록 허용합니다. 일반 앱에서는 필요하지 않습니다."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"이동통신사 메시지 서비스에 고정"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"보유자가 이동통신사 메시지 서비스의 최상위 인터페이스에 고정할 수 있습니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"음성 상호작용 서비스와 상호작용"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"권한을 가진 프로그램이 현재 활성화된 음성 상호작용 서비스와 상호작용하도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"비밀번호 규칙 설정"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"화면 잠금 비밀번호와 PIN에 허용되는 길이와 문자 수를 제어합니다."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"화면 잠금해제 시도 모니터링"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"앱이 패키지가 설치 가능한지 확인할 수 있도록 허용합니다."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"패키지 인증 연결"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"인텐트 필터 인증"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"앱에서 인텐트 필터 인증 여부를 확인하도록 허용합니다."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"인텐트 필터 인증 연결"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"권한을 가진 프로그램이 인텐트 필터 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"외부에서 콘텐츠 제공자에 액세스"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"\'일\'을 줄입니다."</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"\'연도\'를 늘립니다."</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"\'연도\'를 줄입니다."</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"지난달"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"다음 달"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 키"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"취소"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 키"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"분 선택"</string>
     <string name="select_day" msgid="7774759604701773332">"월/일 선택"</string>
     <string name="select_year" msgid="7952052866994196170">"연도 선택"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g>이(가) 선택됨"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 삭제됨"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"업무용 <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"화면 고정을 해제하려면 \'뒤로\'와 \'개요\'를 동시에 길게 터치합니다."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"고정 해제 이전에 PIN 요청"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"고정 해제 이전에 잠금해제 패턴 요청"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"고정 해제 이전에 비밀번호 요청"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"배터리 수명 개선을 위해, 배터리 세이버는 기기의 성능을 줄이고 진동, 위치 서비스 및 대부분의 백그라운드 데이터를 제한합니다. 이메일, 메시지 및 동기화에 의존하는 기타 앱은 앱을 열 때까지 업데이트되지 않을 수 있습니다.\n\n배터리 세이버는 기기를 충전 중일 때는 자동으로 사용 중지됩니다."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>에 정지가 종료될 때까지"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"다운타임이 끝날 때까지"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 7696fbb..3aecf92 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -192,9 +192,19 @@
     <!-- no translation found for roamingTextSearching (8360141885972279963) -->
     <skip />
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi Чалуу"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <!-- no translation found for cfTemplateNotForwarded (1683685883841272560) -->
     <skip />
     <!-- no translation found for cfTemplateForwarded (1302922117498590521) -->
@@ -750,6 +760,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"өткөрүүчүнүн LED индикаторун камера иштеп жатканда өчүрүү"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Камтылган системалык колдонмолорго камеранын LED\'ди колдонуусун өчүрүү мүмкүнчүлүгүн берет."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Алдыртан орнотулган тутум колдонмосуна камера кызматынын тутумдук окуяларын жөнөтүү мүмкүнчүлүгүн берет."</string>
     <!-- no translation found for permlab_brick (2961292205764488304) -->
     <skip />
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"сыналгыны биротоло өчүрүү"</string>
@@ -815,6 +826,10 @@
     <!-- no translation found for permlab_performCdmaProvisioning (5604848095315421425) -->
     <skip />
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Колдонмого CDMA\'ды ишке киргизүү мүмкүнчүлүгүн берет. Кесепеттүү колдонмолор кереги жок CDMA\'ди ишке киргизип башташы мүмкүн."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <!-- no translation found for permlab_locationUpdates (7785408253364335740) -->
     <skip />
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Колдонмого радиодон алынган жайгашкан жердин жаңыртуулары жөнүндө эскертмелерди иштетүү/өчүрүү мүмкүнчүлүгүн берет. Кадимки колдонмолор үчүн эмес."</string>
@@ -1050,6 +1065,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Колдонмого DRM тастыктамаларын алып салуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"оператордун билдирүү кызматына байланышуу"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Кармоочуга оператордун билдирүү кызматынын жогорку деңгээлдеги интерфейсине байланышуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбашы мүмкүн."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"үн катнаштык кызматы менен карым-катнаш кылуу"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Кармоочуга учурдагы жигердүү үн катнаштык кызматы менен карым-катнаш кылуу мүмкүнчүлүгүн берет. Кадимки колдонмолорго талап кылынбайт."</string>
     <!-- no translation found for policylab_limitPassword (4497420728857585791) -->
     <skip />
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Экран кулпусунун сырсөздөрү менен PIN\'дерине уруксат берилген узундук менен белгилерди көзөмөлдөө."</string>
@@ -1463,6 +1480,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Колдонмого топтомдун орнотула тургандыгын текшерүү мүмкүнчүлүгүн берет."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"таңгак текшерүүчүгө байлаштыруу"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Кармоочуга топтом текшергичтеринин атынан өтүнүү мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ниет чыпкасын текшерүү"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Колдонмого ниет чыпкасы текшерилген же текшерилбегенин кароо уруксатын берет."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ниет чыпкасын текшергичке туташуу"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Кармоочуга ниет чыпкасын текшергичтеринин атынан өтүнүү мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбайт."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"сериялык портторго жетүү"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ээсине SerialManager API\'ни колдонуп, серия портуна жеткенге уруксат берүү."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"тышкы контент провайдерлерге жетки алуу"</string>
@@ -2057,6 +2078,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Күндү азайтуу"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Жылды жогорулатуу"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Жылды азайтуу"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Мурунку ай"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Кийинки ай"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Айнуу"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жок кылуу"</string>
@@ -2328,7 +2351,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Мүнөттөрдү тандаңыз"</string>
     <string name="select_day" msgid="7774759604701773332">"Ай жана күндү тандаңыз"</string>
     <string name="select_year" msgid="7952052866994196170">"Жылды тандаңыз"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> тандалды"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> өчүрүлдү"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Жумуш <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Бул экранды бошотуу үчүн Артка жана Көз жүгүртүүнү чогуу басып, кармап туруңуз."</string>
@@ -2339,6 +2361,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Бошотуудан мурун кулпуну ачкан үлгү суралсын"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Бошотуудан мурун сырсөз суралсын"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Батареянын өмүрүн узартуу үчүн, батареяны үнөмдөгүч түзмөгүңүздүн ишинин майнаптуулугун азайтып, дирилдөө, жайгашкан жерди аныктоо кызматтары жана фондук дайындардын көпчүлүгүн чектеп коёт. Электрондук почта, билдирүү жазышуу жана башка шайкештештирүүгө байланыштуу колдонмолор ачылмайынча жаңыртылбай калышы мүмкүн.\n\nБатарея үнөмдөгүч түзмөгүңүз кубатталып жатканда автоматтык түрдө өчүп калат."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Иштебей турган абал <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> аяктамайынча"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Аракетсиз убакытыңыз бүткүчө"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index b8e2cff..a194ea3 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"ປິດໂຣມມິງແບນເນີ"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"ຊອກຫາບໍລິການ"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"ການ​ໂທ Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ປິດ"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ເລືອກໃຊ້ Wi​-Fi ກ່ອນ"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"ເລືອກໃຊ້ເຊລລູລາກ່ອນ"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi​-Fi ເທົ່າ​ນັ້ນ"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ບໍ່ຖືກສົ່ງຕໍ່"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> ຫຼັງຈາກ <xliff:g id="TIME_DELAY">{2}</xliff:g> ວິນາທີ"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ປິດໄຟສັນຍານ LED ເມື່ອນຳໃຊ້ກ້ອງ"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ອະນຸຍາດໃຫ້ແອັບພລິເຄຊັນທີ່ມາກັບໂຕເຄື່ອງ ປິດການນຳໃຊ້ໄຟ LED ໃນກ້ອງຖ່າຍຮູບ."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ລະ​ບົບ​ທີ່​ຕິດ​ຕັ້ງ​ມາ​ກ່ອນ​ສົ່ງ​ເຫດ​ການ​ລະ​ບົບ​ການ​ບໍ​ລິ​ການ​ກ້ອງ​ຖ່າຍ​ຮູບໄດ້."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ປິດການນຳໃຊ້ແທັບເລັດຖາວອນ"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ປິດ​ໃຊ້​ງານໂທລະພາບຖາ​ວອນ"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ປິດການເຮັດວຽກຂອງໂທລະສັບຖາວອນ"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"ເລີ່ມ​ຕົ້ນ​ການ​ຕັ້ງ CDMA ໂທລະພາບໂດຍ​ກົງ"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ເລີ່ມການຕັ້ງຄ່າໂທລະສັບ CDMA ໂດຍກົງ"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"ອະນຸຍາດໃຫ້ແອັບຯເລີ່ມການເຮັດວຽກຂອງ CDMA. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດເລີ່ມການເຮັດວຽກຂອງ CDMA ໂດຍບໍ່ຈຳເປັນ."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"ເລີ່ມ​ຕົ້ນ​ການ​ຕັ້ງ​ແຜ່ນ SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ຈັດ​ການ​ຄຳ​ຂໍ​ການ​ເປີດ​ນຳ​ໃຊ້ SIM. ແອັບ​ອາດ​ຈະ​ເຮັດ​ການ​ເປີດ​ນຳ​ໃຊ້​ໂດຍ​ກົງ ຫຼື​ມອບ​ໃຫ້​ແອັບ​ອື່ນ​ເຮັດ."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ຄວບຄຸມການແຈ້ງເຕືອນອັບເດດສະຖານທີ່"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ອະນຸຍາດໃຫ້ແອັບຯ ເປີດ/ປິດ ການເຮັດວຽກຂອງການແຈ້ງເຕືອນອັບເດດສະຖານທີ່ຈາກວິທະຍຸ. ແອັບຯທົ່ວໄປບໍ່ຈຳເປັນຕ້ອງໃຊ້."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"ເຂົ້າເຖິງຄຸນສົມບັດການເຊັກອິນ"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ພລິ​ເຄ​ຊັນ​ລຶບ​ໃບ​ຮັບ​ຮອງ DRM. ແອັບຯ​ທົ່ວ​ໄປ​ບໍ່​ຄວນ​ຈຳ​ເປັນ​ຕ້ອງ​ໃຊ້."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ຜູກ​ພັນ​ກັບ​ການ​ບໍ​ລິ​ການ​ສົ່ງ​ຂໍ້​ຄວາມ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ອະນຸຍາດໃຫ້ຜູ້ຖືຜູກ​ພັນ​ກັບຕົວ​ປະ​ສານລະດັບສູງສຸດຂອງບໍລິການສົ່ງ​ຂໍ້​ຄວາມ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ດຳ​ເນີນ​ການ​ກັບ​ການ​ບໍ​ລິ​ການ​ດຳ​ເນີນ​ການ​ທາງ​ສຽງ"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"ອະ​ນຸ​ຍາດ​ໃຫ້​ຜູ້​ຖື​ດຳ​ເນີນ​ການ​ກັບ​ການ​ບໍ​ລິ​ການ​ດຳ​ເນີນ​ການ​ທາງ​ສຽງ​ທີ່​ເປີດ​ຢູ່​ປະ​ຈຸ​ບັນ. ບໍ່​ຈຳ​ເປັນ​ສຳ​ລັບ​ແອັບ​ປົກ​ກະ​ຕິ."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ຕັ້ງຄ່າກົດຂອງລະຫັດຜ່ານ"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ຄວບຄຸມຄວາມຍາວ ແລະຕົວອັກສອນທີ່ອະ​ນຸ​ຍາດ​ໃຫ້​ຢູ່​ໃນລະ​ຫັດລັອກໜ້າຈໍ ແລະ PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ຕິດຕາມການພະຍາຍາມປົດລັອກໜ້າຈໍ"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ອະນຸຍາດໃຫ້ແອັບຯຢືນຢັນວ່າແພັກເກດໃດນຶ່ງ ສາມາດຕິດຕັ້ງໄດ້."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ເຊື່ອມໂຍງກັບໂຕຢືນຢັນແພັກເກດ"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຮັດການຮ້ອງຂໍໂຕຢືນຢັນແພັກເກັດ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ຢືນ​ຢັນ​ການ​ກັ່ນ​ຕອງ​ຕາມ​ຕັ້ງ"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ອະ​ນຸ​ຍາດ​ໃຫ້​ແອັບ​ກວດ​ເບິ່ງວ່າ ການ​ກັ່ນ​ຕອງ​ຕາມ​ຕັ້ງ​ໃຈ​ໄວ້​ໄດ້​ຮັບ​ການ​ຢືນ​ຢັນ ຫຼື​ບໍ່."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ຜູກ​ມັດ​ກັບ​ໂຕ​ຢືນ​ຢັນ​ການ​ກັ່ນ​ຕອງ​ຕາມ​ຕັ້ງ​ໃຈ"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງເຮັດການຮ້ອງຂໍໂຕຢືນຢັນການ​ກັ່ນ​ຕອງ​ຕາມ​ຕັ້ງ​ໃຈ. ບໍ່ຈຳເປັນສຳລັບແອັບຯທົ່ວໄປ."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"ເຂົ້າເຖິງພອດຊີຣຽວ"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"ອະນຸຍາດໃຫ້ເຈົ້າຂອງສາມາດເຂົ້າເບິ່ງ serial ports ໂດຍການນຳໃຊ້ SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ເຂົ້າເຖິງຜູ່ສະໜອງເນື້ອຫາພາຍນອກ"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ຫຼຸດຈຳນວນມື້"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ເພີ່ມປີຂຶ້ນ"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ຫຼຸດຈຳນວນປີ"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"​ເດືອນ​ແລ້ວ"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"ເດືອນ​ໜ້າ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ຍົກເລີກ"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ລຶບ"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"ເລືອກນາ​ທີ"</string>
     <string name="select_day" msgid="7774759604701773332">"ເລືອກເດືອນ ແລະ ວັນ"</string>
     <string name="select_year" msgid="7952052866994196170">"ເລືອກ​ປີ"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ຖືກເລືອກແລ້ວ"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ຖືກລຶບແລ້ວ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"​ບ່ອນ​ເຮັດ​ວຽກ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ເພື່ອ​ຖອດ​ການ​ປັກ​ໝຸດ​ໜ້າ​ຈໍ​ນີ້, ສຳ​ຜັດປຸ່ມ ​ກັບ​ຄືນ ແລະ ພາບ​ຮວມ ຄ້າງ​ໄວ້​ພ້ອມ​ກັນ."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"​ຖາມ​ຫາ PIN ກ່ອນ​ຍົກ​ເລີກ​ການປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"​ຖາມ​ຫາ​ຮູບ​ແບບ​ປົດ​ລັອກ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"​ຖາມ​ຫາ​ລະ​ຫັດ​ຜ່ານ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ເພື່ອ​ຊ່ວຍ​ເພີ່ມ​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ, ຕົວ​ປະ​ຢັດ​ໄຟ​ແບັດ​ເຕີ​ຣີ​ຫຼຸດ​ປະ​ສິດ​ທິ​ພາບ​ການ​ເຮັດ​ວຽກ​ຂອງ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ລົງ ແລະ​ຈຳ​ກັດ​ການ​ສັ່ນ, ການ​ບໍ​ລິ​ການ​ຫາທີ່ຕັ້ງ, ແລະ​ຂໍ້​ມູນ​ພື້ນ​ຫຼັງ​ເກືອບ​ທັງ​ໝົດ. ອີ​ເມວ, ການ​ສົ່ງ​ຂໍ້​ຄວາມ, ແລະ​ແອັບອື່ນໆ​ທີ່ອາ​ໄສການ​ຊິງ​ຄ໌​ອາດ​ຈະ​ບໍ່​ອັບ​ເດດ ນອກ​ຈາກວ່າ​ທ່ານ​ເປີດ​ມັນ.\n\nຕົວ​ປະ​ຢັດ​ໄຟ​ແບັດ​ເຕີ​ຣີຈະ​ປິດ​ອັດ​ຕະ​ໂນ​ມັດ ເມື່ອ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ກຳ​ລັງ​ສາກຢູ່."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"ຈົນ​ກວ່າ​ດາວ​ທາມ​ຂອງ​ທ່ານ​ຈະ​ສິ້ນ​ສຸດ​ທີ່ <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"​ຈົນ​ກວ່າ​ເວ​ລາ​ປິດ​ເຮັດ​ວຽກ​ຂອງ​ທ່ານ​ສິ້ນ​ສຸດ​ລົງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f1f81bd..195e91a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -126,9 +126,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Tarptinklinio ryšio reklamjuostė išjungta"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Ieškoma paslaugos"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"„Wi-Fi“ skambinimas"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neperadresuota"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sek."</string>
@@ -587,6 +597,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"neleisti perduoti LED indikatoriaus, kai naudojamas fotoaparatas"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Leidžiama iš anksto įdiegtai sistemos programai išjungti fotoaparato naudojimo indikatoriaus LED."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Iš anksto įdiegtai sistemos programai leidžiama siųsti sistemos įvykius fotoaparato paslaugai."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"visam laikui neleisti planšetinio kompiuterio"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"visam laikui išjungti TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"visam laikui išjungti telefoną"</string>
@@ -635,6 +646,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"tiesiogiai pradėti CDMA TV sąranką"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"tiesiogiai pradėti CDMA telefono sąranką"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Leidžiama programai pradėti CDMA parengimą. Kenkėjiškos programos gali be reikalo pradėti CDMA parengimą."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"valdyti vietos atnaujinimo įspėjimus"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Leidžiama programai įgalinti vietos atnaujinimo pranešimus, gautus iš radijo, ar jų neleisti. Neskirta naudoti įprastoms programoms."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"pasiekti registravimo ypatybes"</string>
@@ -841,6 +856,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Programai leidžiama pašalinti DRM sertifikatus. Neturėtų prireikti naudojant įprastas programas."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"susaistyti su operatoriaus susirašinėjimo žinutėmis paslauga"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Leidžiama savininkui susisaistyti su aukščiausio lygio operatoriaus susirašinėjimo žinutėmis paslaugos sąsaja. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"sąveikauti su balso sąveikos paslauga"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Savininkui leidžiama naudoti šiuo metu suaktyvintą balso sąveikos paslaugą. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nustatyti slaptažodžio taisykles"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Valdykite, kokio ilgio ekrano užrakto slaptažodžius ir PIN kodus galima naudoti."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Stebėti bandymus atrakinti ekraną"</string>
@@ -1138,6 +1155,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leidžiama programai patikrinti, ar paketą galima įdiegti."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"susaistyti su paketo tikrinimo programa"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"patvirtinti tikslinį filtrą"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Leidžiama programai patikrinti, ar tikslinis filtras patvirtintas."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"priskirti tikslinio filtro tvirtin. pr."</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Savininkui leidžiama teikti užklausas patvirtinti tikslinį filtrą. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"pasiekti turinio teikėjus iš išorės"</string>
@@ -1577,6 +1598,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Sumažinti dienų skaičių"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Padidinti metų skaičių"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Sumažinti metų skaičių"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Ankstesnis mėnuo"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Kitas mėnuo"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atšaukti"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ištrinti"</string>
@@ -1831,7 +1854,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Pasirinkite minutes"</string>
     <string name="select_day" msgid="7774759604701773332">"Pasirinkite mėnesį ir dieną"</string>
     <string name="select_year" msgid="7952052866994196170">"Pasirinkite metus"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Pasirinkta: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Ištrinta: <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbo <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Jei norite atsegti šį ekraną, vienu metu palieskite ir palaikykite „Atgal“ ir „Apžvalga“."</string>
@@ -1842,6 +1864,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Prašyti PIN kodo prieš atsegant"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Prašyti atrakinimo piešinio prieš atsegant"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Prašyti slaptažodžio prieš atsegant"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Kad tausotų akumuliatoriaus energiją akumuliatoriaus tausojimo priemonė sumažina įrenginio veikimą ir apriboja vibravimą, vietovės paslaugas bei daugumą foninių duomenų. El. pašto, susirašinėjimo žinutėmis ir kitos programos, kurios veikia sinchronizavimo pagrindu, gali būti neatnaujintos, nebent jas atidarysite.\n\nAkumuliatoriaus tausojimo priemonė automatiškai išjungiama, kai įrenginys įkraunamas."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Kol jūsų prastova baigsis <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kol baigsis prastova"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a55ea95..0d38e51 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -125,9 +125,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Viesabonēšanas reklāmkarogs ir izslēgts."</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Pakalpojuma meklēšana"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi zvani"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nav pāradresēts"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> pēc <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundes(-ēm)"</string>
@@ -586,6 +596,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Atspējot pārraidīšanas LED indikatoru, kad kamera tiek izmantota"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Ļauj iepriekš instalētai sistēmas lietojumprogrammai atspējot LED indikatoru, izmantojot kameru."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Ļauj iepriekš instalētai sistēmas lietojumprogrammai nosūtīt sistēmas notikumu datus uz kameras pakalpojumu."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"neatgriezeniski atspējot planšetdatoru"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"neatgriezeniski atspējot televizora darbību"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"neatgriezeniski atspējot tālruni"</string>
@@ -634,6 +645,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"tieši sākt CDMA TV iestatīšanu"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"tiešā veidā sākt CDMA tālruņa iestatīšanu"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ļauj lietotnei sākt CDMA nodrošināšanu. Ļaunprātīgas lietotnes var sākt CDMA nodrošināšanu bez vajadzības."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrolēt atrašanās vietas atjauninājumu paziņojumus"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ļauj lietotnei iespējot/atspējot paziņojumus no radio saistībā ar atrašanās vietas atjauninājumiem. Atļauja neattiecas uz parastām lietotnēm."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"piekļūt reģistrēšanās rekvizītiem"</string>
@@ -840,6 +855,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Ļauj lietojumprogrammai noņemt DRM sertifikātus. Parastās lietotnēs tas nebūs nepieciešams."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Savienojuma izveide ar mobilo sakaru operatora ziņojumapmaiņas pakalpojumu"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ļauj īpašniekam izveidot savienojumu ar mobilo sakaru operatora ziņojumapmaiņas pakalpojuma augšējā līmeņa saskarni. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"mijiedarboties ar balss pakalpojumu"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Ļauj īpašniekam mijiedarboties ar pašlaik aktīvo balss pakalpojumu. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Paroles kārtulu iestatīšana"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolēt ekrāna bloķēšanas paroļu un PIN garumu un tajos atļautās rakstzīmes."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekrāna atbloķēšanas mēģinājumu pārraudzīšana"</string>
@@ -1137,6 +1154,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ļauj lietotnei verificēt, vai pakotne ir instalējama."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"saistīšana ar pakotnes verificētāju"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificēt mērķa filtru"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Ļauj lietotnei pārbaudīt, vai mērķa filtrs ir verificēts."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"saistīt ar mērķa filtra verificētāju"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Ļauj īpašniekam sūtīt mērķa filtra verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ārēji piekļūt satura nodrošinātājiem"</string>
@@ -1569,6 +1590,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Norādīt agrāku dienu"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Norādīt vēlāku gadu"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Norādīt agrāku gadu"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Iepriekšējais mēnesis"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nākamais mēnesis"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alternēšanas taustiņš"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Atcelt"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Dzēšanas taustiņš"</string>
@@ -1822,7 +1845,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Atlasiet minūtes."</string>
     <string name="select_day" msgid="7774759604701773332">"Atlasiet mēnesi un dienu."</string>
     <string name="select_year" msgid="7952052866994196170">"Atlasiet gadu."</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Atlasīts: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> tika dzēsts."</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Darbā: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Lai atspraustu šo ekrānu, vienlaicīgi pieskarieties pogām “Atpakaļ” un “Pārskats” un turiet tās."</string>
@@ -1833,6 +1855,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pirms atspraušanas pieprasīt PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pirms atspraušanas pieprasīt grafisko atslēgu"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pirms atspraušanas pieprasīt paroli"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Lai paildzinātu akumulatora darbību, akumulatora jaudas taupīšanas režīmā tiek samazināta ierīces veiktspēja un tiek ierobežota vibrācija, atrašanās vietu pakalpojumi un lielākā daļa fona datu. E-pasta, ziņojumapmaiņas un cita veida lietotnes, kuru darbības pamatā ir datu sinhronizācija, var netikt atjauninātas, ja tās neatverat.\n\nTiklīdz tiek sākta ierīces uzlāde, akumulatora jaudas taupīšanas režīms automātiski tiek izslēgts."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Līdz beigsies dīkstāve (<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Līdz beidzas dīkstāve"</string>
diff --git a/core/res/res/values-mcc310-mnc260-af/strings.xml b/core/res/res/values-mcc310-mnc260-af/strings.xml
index 2d4b749..5187a0d 100644
--- a/core/res/res/values-mcc310-mnc260-af/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-af/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi-oproepe is nie beskikbaar nie. Kontak jou diensverskaffer om Wi-Fi-oproepe te aktiveer."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-oproep"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-am/strings.xml b/core/res/res/values-mcc310-mnc260-am/strings.xml
index 126631a..74f711a 100644
--- a/core/res/res/values-mcc310-mnc260-am/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-am/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi ጥሪ ማድረጊያ አይገኝም። የ Wi-Fi ጥሪ ማድረጊያን ለማንቃት የእርስዎን አገልግሎት አቅራቢ ያነጋግሩ።"</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"በWi-Fi ላይ ጥሪዎችን ለማድረግ እና መልዕክቶችን ለመላክ መጀመሪያ የአገልግሎት አቅራቢዎ ይህን አገልግሎት እንዲያዘጋጅልዎ መጠየቅ አለብዎት። ከዚያ ከቅንብሮች ሆነው እንደገና የWi-Fi ጥሪን ያብሩ።"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"የአገልግሎት አቅራቢዎ ጋር ይመዝገቡ"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"የ%s Wi-Fi ጥሪ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ar/strings.xml b/core/res/res/values-mcc310-mnc260-ar/strings.xml
index 1175eec..5a84295 100644
--- a/core/res/res/values-mcc310-mnc260-ar/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ar/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"‏الاتصال عبر Wi-Fi ليس متوفرًا. اتصل بمشغل شبكة الجوّال لتمكين الاتصال عبر Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"‏لإجراء مكالمات وإرسال رسائل عبر Wi-Fi، اطلب من مشغّل شبكة الجوّال أولاً إعداد هذا الجهاز، ثم شغّل الاتصال عبر Wi-Fi مرة أخرى من خلال الإعدادات."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"التسجيل لدى مشغّل شبكة الجوّال"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"‏%s جارٍ الاتصال عبر Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-bg/strings.xml b/core/res/res/values-mcc310-mnc260-bg/strings.xml
index be1d0d3..1207b2b 100644
--- a/core/res/res/values-mcc310-mnc260-bg/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-bg/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Обажданията през Wi-Fi не са налице. Свържете се с оператора си, за да ги активирате."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s – обаждания през Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-bn-rBD/strings.xml b/core/res/res/values-mcc310-mnc260-bn-rBD/strings.xml
index 0135108..67955d5 100644
--- a/core/res/res/values-mcc310-mnc260-bn-rBD/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-bn-rBD/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi কলিং উপলব্ধ নেই৷ Wi-Fi কলিং সক্ষম করতে আপনার পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন৷"</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi এর মাধ্যমে কল করতে ও বার্তা পাঠাতে, প্রথমে আপনার পরিষেবা প্রদানকারীকে এই পরিষেবার সেট আপ করার বিষয়ে জিজ্ঞাসা করুন। তারপরে আবার সেটিংস থেকে Wi-Fi কলিং চালু করুন।"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"আপনার পরিষেবা প্রদানকারীকে নথিভুক্ত করুন"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi কলিং"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ca/strings.xml b/core/res/res/values-mcc310-mnc260-ca/strings.xml
index 5a10585..a0ca207 100644
--- a/core/res/res/values-mcc310-mnc260-ca/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ca/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Les trucades per Wi-Fi no estan disponibles. Contacta amb l\'operador de telefonia mòbil per activar-les."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Trucada de Wi-Fi de: %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-cs/strings.xml b/core/res/res/values-mcc310-mnc260-cs/strings.xml
index 8f1d5dc..dcd7125 100644
--- a/core/res/res/values-mcc310-mnc260-cs/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-cs/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Volání přes Wi-Fi není k dispozici. Kontaktujte operátora, aby volání přes Wi-Fi aktivoval."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Volání přes Wi-Fi: %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-da/strings.xml b/core/res/res/values-mcc310-mnc260-da/strings.xml
index 4e6c2d0..5c23bb4 100644
--- a/core/res/res/values-mcc310-mnc260-da/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-da/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Opkald via Wi-Fi er ikke muligt. Kontakt dit mobilselskab for at aktivere Opkald via Wi-Fi."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-opkald"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-de/strings.xml b/core/res/res/values-mcc310-mnc260-de/strings.xml
index f4838eb..5a9f9c6 100644
--- a/core/res/res/values-mcc310-mnc260-de/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-de/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"WLAN-Anrufe sind nicht möglich. Bitte kontaktieren Sie Ihren Mobilfunkanbieter bezüglich der Aktivierung der WLAN-Telefonie."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s WLAN-Anrufe"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-el/strings.xml b/core/res/res/values-mcc310-mnc260-el/strings.xml
index b3d3aed..55bcda6 100644
--- a/core/res/res/values-mcc310-mnc260-el/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-el/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Η κλήση Wi-Fi δεν είναι διαθέσιμη. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας σας για να ενεργοποιήσετε την κλήση Wi-Fi."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Κλήση Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml b/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml
index 8a9da8f..1d300ea 100644
--- a/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-en-rAU/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi Calling isn\'t available. Contact your operator to enable Wi-Fi Calling."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Register with your operator"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Calling"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml b/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml
index 8a9da8f..1d300ea 100644
--- a/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-en-rGB/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi Calling isn\'t available. Contact your operator to enable Wi-Fi Calling."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Register with your operator"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Calling"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml
index 8a9da8f..1d300ea 100644
--- a/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-en-rIN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi Calling isn\'t available. Contact your operator to enable Wi-Fi Calling."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Register with your operator"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Calling"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml b/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml
index 3f37a6d..940ee00 100644
--- a/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-es-rUS/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Las llamadas con Wi-Fi no están disponibles. Comunícate con el proveedor para habilitar la función."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Llamada por Wi-Fi de %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-es/strings.xml b/core/res/res/values-mcc310-mnc260-es/strings.xml
index 24017c2..2bdb4a3 100644
--- a/core/res/res/values-mcc310-mnc260-es/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-es/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Las llamadas Wi-Fi no están disponibles. Ponte en contacto con tu operador para habilitarlas."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Llamada Wi-Fi de %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-et-rEE/strings.xml b/core/res/res/values-mcc310-mnc260-et-rEE/strings.xml
index 5d3d277..e703dcc 100644
--- a/core/res/res/values-mcc310-mnc260-et-rEE/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-et-rEE/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"WiFi-kõned pole saadaval. WiFi-kõnede lubamiseks võtke ühendust operaatoriga."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s WiFi kaudu helistamine"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-eu-rES/strings.xml b/core/res/res/values-mcc310-mnc260-eu-rES/strings.xml
index 3bcedf7..8fb03d4 100644
--- a/core/res/res/values-mcc310-mnc260-eu-rES/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-eu-rES/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi bidezko deiak ez daude erabilgarri. Gaitzeko, jarri operadorearekin harremanetan."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi bidez deiak egiteko eta mezuak bidaltzeko, eskatu operadoreari zerbitzu hori gaitzeko. Ondoren, aktibatu Wi-Fi bidezko deiak Ezarpenak atalean."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Erregistratu operadorearekin"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi bidezko deiak"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-fa/strings.xml b/core/res/res/values-mcc310-mnc260-fa/strings.xml
index 198d9e2..659a0dd 100644
--- a/core/res/res/values-mcc310-mnc260-fa/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-fa/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"‏تماس از طریق Wi-Fi امکان‌پذیر نیست. برای فعال کردن تماس Wi-Fi، با شرکت مخابراتی‌تان تماس بگیرید."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"‏برای برقراری تماس و ارسال پیام از طریق Wi-Fi، ابتدا از شرکت مخابراتی‌تان درخواست کنید این سرویس را راه‌اندازی کند. سپس دوباره از تنظیمات، تماس Wi-Fi را روشن کنید."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"ثبت نام با شرکت مخابراتی شما"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"‏تماس ‪%s Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-fi/strings.xml b/core/res/res/values-mcc310-mnc260-fi/strings.xml
index a6c0986f..e3b768a 100644
--- a/core/res/res/values-mcc310-mnc260-fi/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-fi/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi-puhelut eivät ole käytettävissä. Pyydä operaattoriasi ottamaan Wi-Fi-puhelut käyttöön."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi-puhelut: %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml b/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml
index 92f5e79..b4f0636 100644
--- a/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-fr-rCA/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"La fonction d\'appel par Wi-Fi n\'est pas disponible. Communiquez avec votre fournisseur de services pour activer les appels par Wi-Fi."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Appels Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-fr/strings.xml b/core/res/res/values-mcc310-mnc260-fr/strings.xml
index b4fe869..b4f0636 100644
--- a/core/res/res/values-mcc310-mnc260-fr/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-fr/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Les appels Wi-Fi ne sont pas disponibles. Contactez votre opérateur pour les activer."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Appels Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-gl-rES/strings.xml b/core/res/res/values-mcc310-mnc260-gl-rES/strings.xml
index 11080f3..2747ab3 100644
--- a/core/res/res/values-mcc310-mnc260-gl-rES/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-gl-rES/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"As chamadas por wifi non están dispoñible. Contacta co teu operador para activar as chamadas por wifi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Para facer chamadas e enviar mensaxes a través da wifi, primeiro pídelle ao teu operador que configure este servizo. A continuación, activa de novo as chamadas wifi en Configuración."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Rexístrate co teu operador"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Chamadas wifi de %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-hi/strings.xml b/core/res/res/values-mcc310-mnc260-hi/strings.xml
index fb65db3..a19f51a 100644
--- a/core/res/res/values-mcc310-mnc260-hi/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-hi/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi कॉलिंग उपलब्‍ध नहीं है. वाई-फ़ाई कॉलिंग सक्षम करने के लिए अपने वाहक से संपर्क करें."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"वाई-फ़ाई से कॉल करने और संदेश भेजने के लिए, सबसे पहले अपने वाहक से इस सेवा को सेट करने के लिए कहें. उसके बाद सेटिंग से पुन: वाई-फ़ाई कॉलिंग चालू करें."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"अपने वाहक के साथ पंजीकृत करें"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s वाई-फ़ाई कॉलिंग"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-hr/strings.xml b/core/res/res/values-mcc310-mnc260-hr/strings.xml
index 7442481..ffd3aa0 100644
--- a/core/res/res/values-mcc310-mnc260-hr/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-hr/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi pozivi nisu dostupni. Obratite se mobilnom operateru radi omogućivanja Wi-Fi poziva."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi pozivanje"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-hu/strings.xml b/core/res/res/values-mcc310-mnc260-hu/strings.xml
index c8241e9..62a4f8c 100644
--- a/core/res/res/values-mcc310-mnc260-hu/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-hu/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"A Wi-Fi-hívás nem érhető el. Engedélyezéséhez forduljon szolgáltatójához."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-hívás"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-hy-rAM/strings.xml b/core/res/res/values-mcc310-mnc260-hy-rAM/strings.xml
index 9296ab4..c5534de 100644
--- a/core/res/res/values-mcc310-mnc260-hy-rAM/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-hy-rAM/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi-ի միջոցով զանգերն անհասանելի են: Դրանք միացնելու համար դիմեք ձեր օպերատորին:"</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi զանգեր"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-in/strings.xml b/core/res/res/values-mcc310-mnc260-in/strings.xml
index d697236..85eb49d 100644
--- a/core/res/res/values-mcc310-mnc260-in/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-in/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Panggilan Wi-Fi tidak tersedia. Hubungi operator untuk mengaktifkan Panggilan Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Untuk melakukan panggilan telepon dan mengirim pesan melalui Wi-Fi, terlebih dahulu minta operator untuk menyiapkan layana ini. Lalu, aktifkan panggilan telepon Wi-Fi lagi dari Setelan."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Mendaftar di operator"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Panggilan Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-is-rIS/strings.xml b/core/res/res/values-mcc310-mnc260-is-rIS/strings.xml
index 1ba95b3..0b96668 100644
--- a/core/res/res/values-mcc310-mnc260-is-rIS/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-is-rIS/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi símtöl eru ekki í boði. Hafðu samband við símafyrirtækið þitt til að virkja Wi-Fi símtöl."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi símtöl"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-it/strings.xml b/core/res/res/values-mcc310-mnc260-it/strings.xml
index f84e8f7..258bd35 100644
--- a/core/res/res/values-mcc310-mnc260-it/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-it/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Le chiamate Wi-Fi non sono disponibili. Contatta il tuo operatore per attivarle."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Chiamata Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-iw/strings.xml b/core/res/res/values-mcc310-mnc260-iw/strings.xml
index b882387..1bcce94 100644
--- a/core/res/res/values-mcc310-mnc260-iw/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-iw/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"‏שיחות ב-Wi-Fi אינן זמינות. צור קשר עם הספק שלך כדי להפעיל שיחות ב-Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"‏כדי להתקשר ולשלוח הודעות ברשת Wi-Fi, תחילה יש לבקש מהספק להגדיר את השירות. לאחר מכן, יש להפעיל שוב התקשרות Wi-Fi מ\'הגדרות\'."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"הירשם אצל הספק"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"‏שיחות Wi-Fi של %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ja/strings.xml b/core/res/res/values-mcc310-mnc260-ja/strings.xml
index 9933a50..a5ae2f8 100644
--- a/core/res/res/values-mcc310-mnc260-ja/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ja/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi通話が利用できません。携帯通信会社に連絡してWi-Fi通話を有効にしてください。"</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi通話(%s)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ka-rGE/strings.xml b/core/res/res/values-mcc310-mnc260-ka-rGE/strings.xml
index d1eadac..ca748da 100644
--- a/core/res/res/values-mcc310-mnc260-ka-rGE/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ka-rGE/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"დარეკვა Wi-Fi-ს მეშვეობით მიუწვდომელია. დაუკავშირდით თქვენს ოპერატორს Wi-Fi-ს მეშვეობით დარეკვის ჩასართავად."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s დარეკვა Wi-Fi-ს მეშვეობით"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-kk-rKZ/strings.xml b/core/res/res/values-mcc310-mnc260-kk-rKZ/strings.xml
index b135e1d..1dee61e 100644
--- a/core/res/res/values-mcc310-mnc260-kk-rKZ/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-kk-rKZ/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi қоңырауы қол жетімді емес. Wi-Fi қоңырауы қосу үшін жабдықтаушыға хабарласыңыз."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi арқылы қоңырау шалу"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-km-rKH/strings.xml b/core/res/res/values-mcc310-mnc260-km-rKH/strings.xml
index b3e86df8..e3cd1b2 100644
--- a/core/res/res/values-mcc310-mnc260-km-rKH/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-km-rKH/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"ការហៅតាម Wi-Fi មិនមាននោះទេ។ សូមទាក់ទងទៅអ្នកផ្តល់សេវាកម្មទូរស័ព្ទរបស់អ្នកដើម្បីបើកដំណើរការហៅតាម Wi-Fi។"</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"ដើម្បីធ្វើការហៅ និងផ្ញើសារតាម Wi-Fi ដំបូងឡើយអ្នកត្រូវស្នើឲ្យក្រុមហ៊ុនរបស់អ្នកដំឡើងសេវាកម្មនេះសិន។ បន្ទាប់មកបើកការហៅតាម Wi-Fi ម្តងទៀតចេញពីការកំណត់។"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"ចុះឈ្មោះជាមួយក្រុមហ៊ុនរបស់អ្នក"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"ការហៅតាមរយៈ Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml
index 6a6378c..f24bed0 100644
--- a/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-kn-rIN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ ಲಭ್ಯವಿಲ್ಲ. ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲು ನಿಮ್ಮ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"ವೈ-ಫೈ ಬಳಸಿಕೊಂಡು ಕರೆ ಮಾಡಲು ಮತ್ತು ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು, ಮೊದಲು ಈ ಸಾಧನವನ್ನು ಹೊಂದಿಸಲು ನಿಮ್ಮ ವಾಹಕವನ್ನು ಕೇಳಿ. ತದನಂತರ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಮತ್ತೆ ವೈ-ಫೈ ಆನ್‌ ಮಾಡಿ."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"ನಿಮ್ಮ ವಾಹಕದಲ್ಲಿ ನೋಂದಾಯಿಸಿಕೊಳ್ಳಿ"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s ವೈ-ಫೈ ಕರೆ ಮಾಡುವಿಕೆ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ko/strings.xml b/core/res/res/values-mcc310-mnc260-ko/strings.xml
index 9a4d89c..0032b35 100644
--- a/core/res/res/values-mcc310-mnc260-ko/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ko/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi 통화를 사용할 수 없습니다. Wi-Fi 통화를 사용하려면 이동통신사에 문의하세요."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi 통화"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ky-rKG/strings.xml b/core/res/res/values-mcc310-mnc260-ky-rKG/strings.xml
index 290ce32..24079bc 100644
--- a/core/res/res/values-mcc310-mnc260-ky-rKG/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ky-rKG/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi Чалуу жеткиликтүү эмес. Wi-Fi Чалууну иштетүү үчүн операторуңузга кайрылыңыз."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Чалуу"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-lo-rLA/strings.xml b/core/res/res/values-mcc310-mnc260-lo-rLA/strings.xml
index 3b96835..49f79016 100644
--- a/core/res/res/values-mcc310-mnc260-lo-rLA/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-lo-rLA/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"ການໂທ Wi-Fi ບໍ່ພ້ອມໃຊ້ງານ. ໃຫ້ຕິດຕໍ່ຫາຜູ້ໃຫ້ບໍລິການຂອງທ່ານເພື່ອເປີດໃຊ້ການໂທ Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"ເພື່ອ​ໂທ ແລະ​ສົ່ງ​ຂໍ້​ຄວາມ​ຢູ່​ເທິງ Wi-Fi, ກ່ອນ​ອື່ນ​ໝົດ​ໃຫ້​ຖ້າມ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ ເພື່ອ​ຕັ້ງ​ການ​ບໍ​ລິ​ການ​ນີ້. ຈາກນັ້ນ​ເປີດການ​ໂທ Wi-Fi ອີກ​ຈາກ​ການ​ຕັ້ງ​ຄ່າ."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"ລົງ​ທະ​ບຽນ​ກັບ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"ການ​ໂທ %s Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-lt/strings.xml b/core/res/res/values-mcc310-mnc260-lt/strings.xml
index 09d151b..1aff275 100644
--- a/core/res/res/values-mcc310-mnc260-lt/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-lt/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"„Wi-Fi“ skambinimo funkcija nepasiekiama. Susisiekite su operatoriumi, kad įgalintumėte „Wi-Fi“ skambinimo funkciją."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"„%s“ „Wi-Fi“ skambinimas"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-lv/strings.xml b/core/res/res/values-mcc310-mnc260-lv/strings.xml
index 2da9a9d..7abedd2 100644
--- a/core/res/res/values-mcc310-mnc260-lv/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-lv/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi zvani nav pieejami. Lai iespējotu Wi-Fi zvanus, sazinieties ar savu mobilo sakaru operatoru."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi zvani"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-mk-rMK/strings.xml b/core/res/res/values-mcc310-mnc260-mk-rMK/strings.xml
index ddf0af6..f342da4 100644
--- a/core/res/res/values-mcc310-mnc260-mk-rMK/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-mk-rMK/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Повикувањето преку Wi-Fi не е достапно. Контактирајте го операторот за да овозможите Повикување преку Wi-Fi."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Повикување преку Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml
index 2565306..764b792 100644
--- a/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ml-rIN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi കോളിംഗ് ലഭ്യമല്ല. Wi-Fi കോളിംഗ് പ്രവർത്തനക്ഷമമാക്കാൻ നിങ്ങളുടെ കാരിയറെ ബന്ധപ്പെടുക."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi വഴി കോളുകൾ വിളിക്കാനും സന്ദേശങ്ങൾ അയയ്‌ക്കാനും ആദ്യം നിങ്ങളുടെ കാരിയറോട് ഈ സേവനം സജ്ജമാക്കാൻ ആവശ്യപ്പെടുക. ക്രമീകരണത്തിൽ നിന്ന് വീണ്ടും Wi-Fi കോളിംഗ് ഓണാക്കുക."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"നിങ്ങളുടെ കാരിയറിൽ രജിസ്റ്റർ ചെയ്യുക"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi കോളിംഗ്"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-mn-rMN/strings.xml b/core/res/res/values-mcc310-mnc260-mn-rMN/strings.xml
index c52dd31..4c97e2e 100644
--- a/core/res/res/values-mcc310-mnc260-mn-rMN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-mn-rMN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi Calling одоогоор боломжгүй байна. Wi-Fi Calling  идэвхжүүлэхийн тулд оператортойгоо холбогдоно уу."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi-аар дуудлага хийх болон мессеж илгээхээр бол эхлээд оператороосоо энэ төхөөрөмжийг тохируулж өгөхийг хүсээрэй. Дараа нь Тохиргооноос Wi-Fi дуудлага хийх үйлдлийг асаагаарай."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Операторт бүртгүүлэх"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi Дуудлага"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-mr-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-mr-rIN/strings.xml
index 86aa1b0..06eceff 100644
--- a/core/res/res/values-mcc310-mnc260-mr-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-mr-rIN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"वाय-फाय कॉलिंग उपलब्‍ध नाही. वाय-फाय कॉलिंग सक्षम करण्‍यासाठी आपल्‍या वाहकाशी संपर्क साधा."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"वाय-फायवरून कॉल करण्यासाठी आणि संदेश पाठविण्यासाठी, प्रथम आपल्या वाहकास ही सेवा सेट करण्यास सांगा. नंतर सेटिंग्जमधून पुन्हा वाय-फाय कॉलिंग चालू करा."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"आपल्या वाहकासह नोंदणी करा"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s वाय-फाय कॉलिंग"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ms-rMY/strings.xml b/core/res/res/values-mcc310-mnc260-ms-rMY/strings.xml
index 94e9705..dafb3bd 100644
--- a/core/res/res/values-mcc310-mnc260-ms-rMY/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ms-rMY/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Panggilan Wi-Fi tidak tersedia. Hubungi pembawa anda untuk mendayakan Panggilan Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Untuk membuat panggilan dan menghantar mesej melalui Wi-Fi, mula-mula minta pembawa anda untuk menyediakan perkhidmatan ini. Kemudian hidupkan panggilan Wi-Fi semula daripada Tetapan."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Daftar dengan pembawa anda"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Panggilan Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-my-rMM/strings.xml b/core/res/res/values-mcc310-mnc260-my-rMM/strings.xml
index bf624ce..25ea191 100644
--- a/core/res/res/values-mcc310-mnc260-my-rMM/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-my-rMM/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"ဝိုင်ဖိုင်ခေါ်ဆိုမှု မရပါ။ ဝိုင်ဖိုင် ခေါ်နိုင်ရန် သင်၏ ဖုန်းဝန်ဆောင်မှုပေးသူအား ဆက်သွယ်ပါ။"</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"ဝိုင်ဖိုင်သုံး၍ ဖုန်းခေါ်ဆိုရန်နှင့် မက်စေ့ဂျ်များပို့ရန်၊ ဤဝန်ဆောင်မှုအား စတင်သုံးနိုင်ရန်အတွက် သင့် မိုဘိုင်းဝန်ဆောင်မှုအား ဦးစွာမေးမြန်းပါ။ ထို့နောက် ဆက်တင်မှတဆင့် ဝိုင်ဖိုင် ခေါ်ဆိုမှုအား ထပ်ဖွင့်ပါ။"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"သင့် မိုဘိုင်းဝန်ဆောင်မှုဖြင့် မှတ်ပုံတင်ရန်"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s ဝိုင်ဖိုင် ခေါ်ဆိုမှု"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-nb/strings.xml b/core/res/res/values-mcc310-mnc260-nb/strings.xml
index c4e9f6e..ee5688d 100644
--- a/core/res/res/values-mcc310-mnc260-nb/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-nb/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi-anrop er ikke tilgjengelig. Ta kontakt med operatøren din for å slå på Wi-Fi-anrop."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-anrop"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ne-rNP/strings.xml b/core/res/res/values-mcc310-mnc260-ne-rNP/strings.xml
index 2ba19e5..852a5d7 100644
--- a/core/res/res/values-mcc310-mnc260-ne-rNP/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ne-rNP/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi कलिङ उपलब्ध छैन। Wi-Fi कलिङ सक्षम पार्न तपाईँको वाहकलाई सम्पर्क गर्नुहोस्।"</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi बाट कल गर्न र सन्देशहरू पठाउन, सबभन्दा पहिला यो सेवा सेटअप गर्न तपाईँको वाहकलाई भन्नुहोस्। त्यसपछि फेरि सेटिङहरूबाट Wi-Fi कलिङ खोल्नुहोस्।"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"तपाईँको वाहकसँग दर्ता गर्नुहोस्"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi कलिङ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-nl/strings.xml b/core/res/res/values-mcc310-mnc260-nl/strings.xml
index 20b7aa4..6509ffb 100644
--- a/core/res/res/values-mcc310-mnc260-nl/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-nl/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Bellen via wifi is niet beschikbaar. Neem contact op met uw provider om bellen via wifi in te schakelen."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Bellen via wifi van %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-pl/strings.xml b/core/res/res/values-mcc310-mnc260-pl/strings.xml
index ef3e2e3..5c047f6 100644
--- a/core/res/res/values-mcc310-mnc260-pl/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-pl/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Połączenia przez Wi-Fi są niedostępne. Skontaktuj się z operatorem sieci, by je włączyć."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Połączenia przez Wi-Fi (%s)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml b/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml
index 8ea4cb4c..140b8d1 100644
--- a/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-pt-rPT/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"As chamadas Wi-Fi não estão disponíveis. Contacte o seu operador para as ativar."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Chamadas por Wi-Fi da %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-pt/strings.xml b/core/res/res/values-mcc310-mnc260-pt/strings.xml
index e01fc4a..bad49c3 100644
--- a/core/res/res/values-mcc310-mnc260-pt/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-pt/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"A chamada por Wi-Fi não está disponível. Entre em contato com sua operadora para ativá-la."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Faça registro na sua operadora"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s chamada Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ro/strings.xml b/core/res/res/values-mcc310-mnc260-ro/strings.xml
index 0a78caa..b547cd3 100644
--- a/core/res/res/values-mcc310-mnc260-ro/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ro/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Apelarea prin Wi-Fi nu este disponibilă. Contactați-vă operatorul pentru a activa Apelarea prin Wi-Fi."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Apelare prin Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ru/strings.xml b/core/res/res/values-mcc310-mnc260-ru/strings.xml
index 3266bdb..29ac79c 100644
--- a/core/res/res/values-mcc310-mnc260-ru/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ru/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Звонки по Wi-Fi недоступны. Чтобы включить эту функцию, свяжитесь со своим оператором."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Звонки по Wi-Fi (%s)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-si-rLK/strings.xml b/core/res/res/values-mcc310-mnc260-si-rLK/strings.xml
index d1e5c27..de00901 100644
--- a/core/res/res/values-mcc310-mnc260-si-rLK/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-si-rLK/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi ඇමතීම ලබාගත නොහැක. Wi-Fi ඇමතීම ක්‍රියාත්මක කිරීමට ඔබගේ වාහකයා සම්බන්ධ කරගන්න."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi හරහා ඇමතුම් සිදු කිරීමට සහ පණිවිඩ යැවීමට, පළමුව මෙම සේවාව පිහිටුවන ලෙස ඔබේ වාහකයෙන් ඉල්ලන්න. අනතුරුව සැකසීම් වෙතින් Wi-Fi ඇමතුම නැවත ක්‍රියාත්මක කරන්න."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"ඔබගේ වාහකය සමඟ ලියාපදිංචි වන්න"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi අමතමින්"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-sk/strings.xml b/core/res/res/values-mcc310-mnc260-sk/strings.xml
index 2adccc8..eb8b5f8 100644
--- a/core/res/res/values-mcc310-mnc260-sk/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-sk/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Volanie cez Wi-Fi nie je k dispozícii. Kontaktujte svojho operátora a požiadajte ho o povolenie volania cez Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Ak chcete volať a odosielať správy prostredníctvom siete Wi-Fi, kontaktujte najskôr svojho operátora v súvislosti s nastavením tejto služby. Potom opäť zapnite v Nastaveniach volanie cez Wi-Fi."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Registrujte sa so svojím operátorom"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Volanie siete Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-sl/strings.xml b/core/res/res/values-mcc310-mnc260-sl/strings.xml
index e4bedcf..e18d778 100644
--- a/core/res/res/values-mcc310-mnc260-sl/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-sl/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Klicanje prek Wi-Fi-ja ni na voljo. Obrnite se na operaterja, da vam omogoči klicanje prek Wi-Fi-ja."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Klicanje prek Wi-Fi-ja (%s)"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-sr/strings.xml b/core/res/res/values-mcc310-mnc260-sr/strings.xml
index 6b00845..6fb8e20 100644
--- a/core/res/res/values-mcc310-mnc260-sr/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-sr/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Позивање преко Wi-Fi-ја није доступно. Контактирајте мобилног оператера да бисте омогућили позивање преко Wi-Fi-ја."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Wi-Fi позивање преко оператера %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-sv/strings.xml b/core/res/res/values-mcc310-mnc260-sv/strings.xml
index 4984914..c3157dc 100644
--- a/core/res/res/values-mcc310-mnc260-sv/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-sv/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Det går inte att ringa Wi-Fi-samtal. Kontakta operatören om du vill aktivera Wi-Fi-samtal."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi-samtal"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-sw/strings.xml b/core/res/res/values-mcc310-mnc260-sw/strings.xml
index eab7344..c7e46c6 100644
--- a/core/res/res/values-mcc310-mnc260-sw/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-sw/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Huduma ya Upigaji simu kwa Wi-Fi haipatikani. Wasiliana na mtoa huduma wako ili awashe Upigaji simu kwa Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Kupiga simu na kutuma ujumbe kupitia Wi-Fi, mwambie mtoa huduma wako asanidi huduma hii kwanza. Kisha washa upigaji simu kwa Wi-Fi tena kutoka Mipangilio."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Jisajili na mtoa huduma wako"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Upigaji Simu kwa Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ta-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-ta-rIN/strings.xml
index e7da4b6..144bc95 100644
--- a/core/res/res/values-mcc310-mnc260-ta-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ta-rIN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"வைஃபை அழைப்பு கிடைக்கவில்லை. வைஃபை அழைப்பை இயக்க, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"வைஃபை மூலம் அழைக்க மற்றும் செய்திகள் அனுப்ப, முதலில் மொபைல் நிறுவனத்திடம் இந்தச் சேவையை அமைக்குமாறு கேட்கவும். பிறகு அமைப்புகளில் மீண்டும் வைஃபை அழைப்பை இயக்கவும்."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"உங்கள் மொபைல் நிறுவனத்தில் பதிவுசெய்யவும்"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s வைஃபை அழைப்பு"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-te-rIN/strings.xml b/core/res/res/values-mcc310-mnc260-te-rIN/strings.xml
index 98de7b7..ef94c4c 100644
--- a/core/res/res/values-mcc310-mnc260-te-rIN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-te-rIN/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi కాలింగ్ అందుబాటులో లేదు. Wi-Fi కాలింగ్‌ను ప్రారంభించడానికి మీ క్యారియర్‌ను సంప్రదించండి."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fiలో కాల్‌లు చేయడం మరియు సందేశాలు పంపడం కోసం ముందుగా ఈ సేవను సెటప్ చేయడానికి మీ క్యారియర్‌ను అడగండి. ఆపై సెట్టింగ్‌ల నుండి మళ్లీ Wi-Fi కాలింగ్‌ను ఆన్ చేయండి."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"మీ క్యారియర్‌తో నమోదు చేయండి"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi కాలింగ్"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-th/strings.xml b/core/res/res/values-mcc310-mnc260-th/strings.xml
index eb64b8f..4525a80 100644
--- a/core/res/res/values-mcc310-mnc260-th/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-th/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"การโทรผ่าน Wi-Fi ไม่พร้อมใช้งาน โปรดติดต่อผู้ให้บริการของคุณเพื่อเปิดใช้การโทรผ่าน Wi-Fi"</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"กำลังเรียก Wi-Fi ของ %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-tl/strings.xml b/core/res/res/values-mcc310-mnc260-tl/strings.xml
index 1ac32d0..5557835 100644
--- a/core/res/res/values-mcc310-mnc260-tl/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-tl/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Hindi available ang Pagtawag sa pamamagitan ng Wi-Fi. Makipag-ugnayan sa iyong carrier upang i-enable ang Pagtawag sa pamamagitan ng Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Upang tumawag at magpadala ng mga mensahe sa pamamagitan ng Wi-Fi, hilingin muna sa iyong carrier na i-set up ang serbisyong ito. Pagkatapos ay muling i-on ang pagtawag sa Wi-Fi mula sa Mga Setting."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Magparehistro sa iyong carrier"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Pagtawag sa Pamamagitan ng Wi-Fi ng %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-tr/strings.xml b/core/res/res/values-mcc310-mnc260-tr/strings.xml
index 5a479f7..6c91869 100644
--- a/core/res/res/values-mcc310-mnc260-tr/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-tr/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Kablosuz Çağrı kullanılamıyor. Kablosuz Çağrı özelliğini etkinleştirmek için operatörünüzle iletişim kurun."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Kablosuz Çağrı"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-uk/strings.xml b/core/res/res/values-mcc310-mnc260-uk/strings.xml
index f878528..0c21309 100644
--- a/core/res/res/values-mcc310-mnc260-uk/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-uk/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Ви не можете телефонувати через Wi-Fi. Щоб увімкнути цю функцію, зв’яжіться з оператором."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Щоб телефонувати або надсилати повідомлення через Wi-Fi, спочатку попросіть свого оператора налаштувати цю послугу. Після цього ввімкніть дзвінки через Wi-Fi у налаштуваннях."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Зареєструйтеся в оператора"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Дзвінок через Wi-Fi від оператора %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-ur-rPK/strings.xml b/core/res/res/values-mcc310-mnc260-ur-rPK/strings.xml
index a9e56d2..4c81ffd 100644
--- a/core/res/res/values-mcc310-mnc260-ur-rPK/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-ur-rPK/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"‏Wi-Fi کالنگ دستیاب نہیں ہے۔ Wi-Fi کالنگ فعال کرنے کیلئے اپنے کیریئر سے رابطہ کریں۔"</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"‏‎%s Wi-Fi کالنگ"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-uz-rUZ/strings.xml b/core/res/res/values-mcc310-mnc260-uz-rUZ/strings.xml
index 26c6cd8..19c8f2e 100644
--- a/core/res/res/values-mcc310-mnc260-uz-rUZ/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-uz-rUZ/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Wi-Fi qo‘ng‘iroq mavjud emas. Wi-Fi qo‘ng‘iroqni yoqish uchun tarmoq operatori bilan bog‘laning."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Wi-Fi orqali qo‘ng‘iroqlarni amalga oshirish va xabarlar bilan almashinish uchun uyali aloqa operatoringizdan ushbu xizmatni yoqib qo‘yishni so‘rashingiz lozim. Keyin sozlamalarda Wi-Fi qo‘ng‘irog‘i imkoniyatini yoqib olishingiz mumkin."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Mobil operatoringiz yordamida ro‘yxatdan o‘ting"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi qo‘ng‘iroqlar"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-vi/strings.xml b/core/res/res/values-mcc310-mnc260-vi/strings.xml
index 242ec73..5ffcd26 100644
--- a/core/res/res/values-mcc310-mnc260-vi/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-vi/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Tính năng Gọi qua Wi-Fi không khả dụng. Hãy liên hệ với nhà cung cấp dịch vụ để bật tính năng Gọi qua Wi-Fi."</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"Gọi điện qua Wi-Fi %s"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml b/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml
index a359441..c50bdef 100644
--- a/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-zh-rCN/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"WLAN 通话功能不可用。请与您的运营商联系,以便启用 WLAN 通话功能。"</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s WLAN 通话功能"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml b/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml
index 984e55f..2fd3c42 100644
--- a/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-zh-rHK/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"無法使用 Wi-Fi 通話。請聯絡您的流動網絡供應商,以啟用 Wi-Fi 通話。"</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"如要透過 Wi-Fi 撥打電話及傳送訊息,請先向您的流動網絡供應商要求設定此服務。然後再次從設定開啟 Wi-Fi 通話。"</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"向您的流動網絡供應商註冊"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi 通話"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml b/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml
index 6a82063..bde0baa 100644
--- a/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-zh-rTW/strings.xml
@@ -22,8 +22,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"無法使用 Wi-Fi 通話功能。請與您的行動通訊業者聯絡,為您啟用 Wi-Fi 通話功能。"</item>
-  </string-array>
+    <!-- no translation found for wfcOperatorErrorAlertMessages:0 (7239039348648848288) -->
+    <!-- no translation found for wfcOperatorErrorNotificationMessages:0 (483847327467331298) -->
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s Wi-Fi 通話"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260-zu/strings.xml b/core/res/res/values-mcc310-mnc260-zu/strings.xml
index 2c06e9a..cc32b1e 100644
--- a/core/res/res/values-mcc310-mnc260-zu/strings.xml
+++ b/core/res/res/values-mcc310-mnc260-zu/strings.xml
@@ -22,8 +22,11 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string-array name="wfcOperatorErrorMessages">
-    <item msgid="931634632269046788">"Ukushaya kwe-Wi-Fi akutholakali. Xhumana nenkampani yakho yenethiwekhi ukuze unike amandla ukushaya kwe-Wi-Fi."</item>
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Ukuze wenze amakholi uphinde uthumele imilayezo nge-Wi-FI, qala ucele inkampani yakho yenethiwekhi ukuthi isethe le divayisi. Bese uvula ukushaya kwe-Wi-FI futhi kusukela kuzilungiselelo."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Bhalisa ngenkampani yakho yenethiwekhi"</item>
   </string-array>
     <string name="wfcSpnFormat" msgid="4982938551498609442">"%s ukushaya kwe-Wi-Fi"</string>
 </resources>
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
index 75b1b53..dc79877 100644
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ b/core/res/res/values-mcc310-mnc260/strings.xml
@@ -25,9 +25,13 @@
     <string-array name="wfcOperatorErrorCodes" translatable="false">
         <item>REG09</item>
     </string-array>
-    <!-- WFC Operator Error Messages -->
-    <string-array name="wfcOperatorErrorMessages">
-        <item>Wi-Fi Calling isn\&apos;t available. Contact your carrier to enable Wi-Fi Calling.</item>
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
     </string-array>
     <!-- Template for showing cellular network operator name while WFC is active -->
     <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 76e05c8..d0822f2 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Банерот со роаминг е исклучен"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Пребарување за услуга"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Повикување преку Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не е препратено"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> по <xliff:g id="TIME_DELAY">{2}</xliff:g> секунди"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"оневозможи пренесување на LED показателот при употреба на фотоапаратот"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Овозможува претходно инсталираниот систем на апликацијата да оневозможи фотоапаратот да го користи LED показателот."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Дозволува претходно инсталираната системска апликација да ги испраќа системските настани на успугата за фотоапарат."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"трајно оневозможи го таблетот"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"трајно оневозможи го телевизорот"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"трајно оневозможи го телефонот"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"директно стартувај поставување CDMA на телевизорот"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"директно вклучи подесувања за телефон CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дозволува апликацијата да започне одредување на ЦДМА. Злонамерните апликации може непотребно да започнат со одредување на ЦДМА."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"контролирај известувања за ажурирање локација"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дозволува апликацијата да овозможува/оневозможува известувања за ажурирање локација од радио. Да не се користи за стандардни апликации."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"пристапи кон својства за пријавување"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Дозволува апликација да отстранува ДРМ-сертификати. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"сврзување со давателот на услугата за пораки"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Дозволува сопственикот да се сврзе со интерфејсот од највисоко ниво на давателот на услугата за пораки. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"комуницирај со услуга за гласовна интеракција"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Дозволува интеракција на сопственикот со тековната услуга за гласовна интеракција. Не треба да се користи за стандардни апликации."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подеси правила за лозинката"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролирај ги должината и знаците што се дозволени за лозинки и ПИН-броеви за отклучување екран."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Следи ги обидите за отклучување на екранот"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволува апликацијата да провери дали пакетот може да се инсталира."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"врзи се со проверувач на пакет"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволува сопственикот да поднесува барања до верификаторите на пакети. Не треба да се користи за стандардни апликации."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"провери го наменскиот филтер"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Дозволува апликацијата да проверува дали наменскиот филтер е проверен или не."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"врзано со наменски проверувач на филтер"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Дозволува сопственикот да поднесува барања до наменските проверувачи на филтри. Не треба да се користи за стандардни апликации."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"пристапи кон сериски порти"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Му овозможува на сопственикот да пристапи кон сериски порти употребувајќи го SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"однадвор пристапи кон обезбедувачи на содржина"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Намали ден"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Зголеми година"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Намали година"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Претходниот месец"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Следниот месец"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Копче „Alt“"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Копче „Откажи“"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Копче „Избриши“"</string>
@@ -1815,7 +1838,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Избери минути"</string>
     <string name="select_day" msgid="7774759604701773332">"Избери месец и ден"</string>
     <string name="select_year" msgid="7952052866994196170">"Избери година"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Избрано <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Избришано <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Работа <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"За да го откачите екранот, допрете и задржете Назад и Краток преглед во исто време."</string>
@@ -1826,6 +1848,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Прашај за ПИН пред откачување"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Прашај за шема за отклучување пред откачување"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Прашај за лозинка пред откачување"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"За да ви помогне да ја подобрите трајноста на батеријата, штедачот на батеријата ја намалува изведбата на уредот и го ограничува вибрирањето, услугите за локација и повеќето податоци од заднина. Е-поштата, испраќањето пораки и другите апликации кои се потпираат на синхронизација можеби нема да се ажурираат доколку не ги отворите.\n\nШтедачот на батеријата автоматски се исклучува кога уредот се полни."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Додека не заврши паузата во <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Додека да заврши паузата"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index e18cc6c..f4d5a1e 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"റോമിംഗ് ബാനർ ഓഫാക്കുക"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"സേവനത്തിനായി തിരയുന്നു"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi കോളിംഗ്"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ഓഫ്"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi തിരഞ്ഞെടുത്തിരിക്കുന്നു"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"സെല്ലുലാർ തിരഞ്ഞെടുത്തിരിക്കുന്നു"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi മാത്രം"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: കൈമാറിയില്ല"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> നിമിഷത്തിനുശേഷം <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ക്യാമറ ഉപയോഗത്തിലായിരിക്കുമ്പോൾ ട്രാൻസ്‌മിറ്റ് ഇൻഡിക്കേറ്റർ LED പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ക്യാമറയുടെ ഇൻഡിക്കേറ്റർ LED-യുടെ ഉപയോഗം പ്രവർത്തനരഹിതമാക്കാൻ മുൻകൂട്ടി ഇൻസ്റ്റാളുചെയ്‌ത സിസ്റ്റം അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"ക്യാമറ സേവന സിസ്റ്റം ഇവന്റുകൾ അയയ്‌ക്കാൻ മുൻകൂട്ടി ഇൻസ്റ്റാളുചെയ്‌ത ഒരു സിസ്റ്റം അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ശാശ്വതമായി ടാബ്‌ലെറ്റ് പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ടിവിയെ ശാശ്വതമായി പ്രവർത്തനരഹിതമാക്കുക"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ശാശ്വതമായി ഫോൺ പ്രവർത്തനരഹിതമാക്കുക"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA സജ്ജീകരണം നേരിട്ട് ആരംഭിക്കുന്നു"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA ഫോൺ സജ്ജീകരണം നേരിട്ട് ആരംഭിക്കുക"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMA പ്രൊവിഷനിംഗ് ആരംഭിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ദോഷകരമായ അപ്ലിക്കേഷനുകൾ അനാവശ്യമായി CDMA പ്രൊവിഷനിംഗ് ആരംഭിച്ചേക്കാം."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM കാർഡ് സജ്ജമാക്കാൻ ആരംഭിക്കുക"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"SIM സജീവമാക്കൽ അഭ്യർത്ഥനകൾ കൈകാര്യം ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. അപ്ലിക്കേഷൻ നേരിട്ട് ആക്റ്റിവേഷൻ ചെയ്യുകയോ മറ്റൊരു അപ്ലിക്കേഷൻ നിയുക്തമാക്കുകയോ ചെയ്യാം."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ലൊക്കേഷൻ അപ്‌ഡേറ്റ് അറിയിപ്പുകൾ നിയന്ത്രിക്കുക"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"റേഡിയോയിൽ നിന്ന് ലൊക്കേഷൻ അപ്ഡേറ്റ് അറിയിപ്പുകൾ പ്രവർത്തനക്ഷമമാക്കുന്നതിന്/പ്രവർത്തനരഹിതമാക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്കായുഌഅ ഉപയോഗത്തിനല്ല."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"ചെക്ക്ഇൻ പ്രോപ്പർട്ടികൾ ആക്‌സസ്സ് ചെയ്യുക"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM സർട്ടിഫിക്കറ്റുകൾ നീക്കംചെയ്യുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"കാരിയർ സന്ദേശമയയ്‌ക്കൽ സേവനത്തിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"ഒരു കാരിയർ സന്ദേശമയയ്‌ക്കൽ സേവനത്തിന്റെ ഉയർന്ന നിലയിലുള്ള ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കാൻ ദാതാവിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"വോയ്‌സ് ഇന്ററാക്ഷൻ സേവനവുമായി ഇടപെടുക"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"നിലവിൽ സജീവമായിരിക്കുന്ന വോയ്‌സ് ഇന്ററാക്ഷൻ സേവനവുമായി ഇടപെടാൻ ഉടമയെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"പാസ്‌വേഡ് നിയമങ്ങൾ സജ്ജീകരിക്കുക"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"സ്‌ക്രീൻ ലോക്ക് പാസ്‌വേഡുകളിലും PIN-കളിലും അനുവദിച്ചിരിക്കുന്ന ദൈർഘ്യവും പ്രതീകങ്ങളും നിയന്ത്രിക്കുക."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"സ്‌ക്രീൻ അൺലോക്ക് ശ്രമങ്ങൾ നിരീക്ഷിക്കുക"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ഒരു പാക്കേജ് ഇൻസ്റ്റാളുചെയ്യാനാവുന്നതാണോ എന്ന് പരിശോധിച്ചുറപ്പിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ഒരു പാക്കേജ് വെരിഫയറുമായി ബന്ധപ്പെടുത്തുക"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"പാക്കേജ് പരിശോധകരുടെ അഭ്യർത്ഥനകൾക്ക് ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ഉദ്ദേശിക്കുന്ന ഫിൽട്ടർ പരിശോധിച്ചുറപ്പിക്കുക"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ഒരു ഉദ്ദേശിക്കുന്ന ഫിൽട്ടർ പരിശോധിച്ചുറപ്പിച്ചോ ഇല്ലയോ എന്ന് പരിശോധിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ഒരു ഉദ്ദേശിക്കുന്ന ഫിൽട്ടർ പരിശോധകനിലേക്ക് ബന്ധിപ്പിക്കുക"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ഉദ്ദേശിക്കുന്ന ഫിൽട്ടർ പരിശോധകരുടെ അഭ്യർത്ഥനകൾക്ക് ഉടമയെ അനുവദിക്കുന്നു. സാധാരണ അപ്ലിക്കേഷനുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"സീരിയൽ പോർട്ടുകൾ ആക്‌സസ്സ് ചെയ്യുക"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API ഉപയോഗിക്കുന്ന സീരിയൽ പോർട്ടുകൾ ആക്‌സസ്സ് ചെയ്യാൻ ദാതാവിനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"ഉള്ളടക്ക ദാതാക്കളെ ബാഹ്യമായി ആക്‌സസ്സുചെയ്യുക"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ദിവസം കുറയ്ക്കുക"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"വർഷം വർദ്ധിപ്പിക്കുക"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"വർഷം കുറയ്‌ക്കുക"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"മുമ്പത്തെ മാസം"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"അടുത്ത മാസം"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"റദ്ദാക്കുക"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ഇല്ലാതാക്കുക"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"മിനിറ്റ് തിരഞ്ഞെടുക്കുക"</string>
     <string name="select_day" msgid="7774759604701773332">"മാസവും ദിവസവും തിരഞ്ഞെടുക്കുക"</string>
     <string name="select_year" msgid="7952052866994196170">"വർഷം തിരഞ്ഞെടുക്കുക"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> തിരഞ്ഞെടുത്തു"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ഇല്ലാതാക്കി"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ഔദ്യോഗികം <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ഈ സ്‌ക്രീൻ അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'കാഴ്ച\' എന്നിവ ഒരേ സമയം സ്‌പർശിച്ച് പിടിക്കുക."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പിൻ ആവശ്യപ്പെടുക"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടുക"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"അൺപിൻ ചെയ്യുന്നതിനുമുമ്പ് പാസ്‌വേഡ് ആവശ്യപ്പെടുക"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ബാറ്ററി ആയുസ്സ് മെച്ചപ്പെടുത്താൻ സഹായിക്കുന്നതിന്, ബാറ്ററി സേവർ നിങ്ങളുടെ ഉപകരണത്തിന്റെ പ്രകടനത്തെ കുറയ്‌ക്കുകയും വൈബ്രേഷനെയും മിക്ക പശ്ചാത്തല വിവരത്തെയും പരിമിതപ്പെടുത്തുകയും ചെയ്യുന്നു. ഇമെയിൽ, സന്ദേശമയയ്‌ക്കൽ, സമന്വയിപ്പിക്കലിനെ ആശ്രയിച്ചുള്ള മറ്റ് അപ്ലിക്കേഷനുകൾ എന്നിവ നിങ്ങൾ തുറക്കുന്നതുവരെ അപ്‌ഡേറ്റുചെയ്യാനിടയില്ല.\n\nനിങ്ങളുടെ ഉപകരണം ചാർജ്ജുചെയ്യുമ്പോൾ ബാറ്ററി സേവർ സ്വയം ഓഫാകും."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-ന് നിങ്ങളുടെ കാലാവധി അവസാനിക്കുന്നതുവരെ"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"പ്രവർത്തനരഹിതമായിരിക്കുന്ന സമയം അവസാനിക്കുന്നതുവരെ"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index da75a4a..eb842c9 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Баннергүй рүүминг"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Үйлчилгээг хайж байна…"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi Calling"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Идэвхгүй"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi илүү эрхэмлэдэг"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Үүрэн сүлжээг илүү эрхэмлэдэг"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Зөвхөн Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: дамжуулагдаагүй"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> <xliff:g id="TIME_DELAY">{2}</xliff:g> секундын дараа"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"камер ашиглаж байх үед дамжууллыг заагч LED-г идэвхгүй болгох"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Урьдчилан суусан систем аппликешн нь камер ашиглалтыг заасан LED-г идэвхгүй болгох боломжтой."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Урьдчилан суулгасан системийн аппликейшнд Камерын үйлчилгээний системийн ажиллагаануудыг илгээхийг зөвшөөрнө."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"таблетыг бүрмөсөн идэвхгүй болгох"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"телевиз-г бүр мөсөн идэвхгүй болгох"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"утсыг бүрмөсөн идэвхгүй болгох"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA телевиз-ийн тохиргоог шууд эхлүүлэх"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA утасны тохиргоог шууд эхлүүлэх"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Апп нь CDMA провишныг эхлүүлэх боломжтой. Хортой апп нь шаардлагагүй байхад CDMA провишныг эхлүүлж болзошгүй."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM картын тохиргоог эхлүүлэх"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Апп-д SIM идэвхжүүлэх хүсэлтүүдийг удирдахыг зөвшөөрнө. Апп нь шууд идэвхжүүлэлт хийх эсвэл өөр апп руу дамжуулж болно."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"байршил шинэчлэх мэдэгдлийг удирдах"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Апп нь радиогоос ирсэн байршил шинэчлэх мэдэгдлийг идэвхтэй/идэвхгүй болгох боломжтой. Энгийн апп-д хэрэглэглэхгүй."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"бүртгэх пропертид хандах"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Аппликешнд DRM сертификатыг устгахыг зөвшөөрнө. Энгийн апп-уудад хэзээ ч ашиглагдахгүй."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"зөөгч зурвасын үйлчилгээнд холбох"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Эзэмшигчид зөөгч зурвасын үйлчилгээний түвшний интерфэйст холбогдохыг зөвшөөрдөг. Энгийн апп-д шаардлагагүй."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"дуут харилцах үйлчилгээг ашиглах"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Эзэмшигчид одоогоор идэвхтэй байгаа дуут харилцах үйлчилгээг ашиглахыг зөвшөөр. Энэ нь энгийн апп-уудад огт шаардлагагүй."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Нууц үгний дүрмийг тохируулах"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Дэлгэц түгжих нууц үг болон ПИН кодны урт болон нийт тэмдэгтийн уртыг хянах."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Дэлгэц тайлах оролдлогыг хянах"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Апп нь багцыг суулгаж болох эсэхийг шалгах боломжтой."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"багц тулгагчтэй холбох"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Эзэмшигч нь багц тулгагчдад хүсэлт тавих боломжтой. Энгийн апп-д хэрэглэгдэхгүй."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"зориулалтын шүүлтүүрийг баталгаажуулах"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Зориулалтын шүүлтүүрийг баталгаажуулсан эсэхээс үл хамааран апп-д шалгах зөвшөөрөл өгөх"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"зориулалтын шүүлтүүр шалгагч руу холбох"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Эзэмшигчид зориулалтын шүүлтүүрийг шалгах хүсэлт гаргахыг зөвшөөрөх. Энэ нь энгийн апп-уудад огт шаардлагагүй."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"сериал портруу хандах"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Эзэмшигч нь SerialManager API ашиглан сериал портод хандах боломжтой."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"контент нийлүүлэгчид гаднаас хандах"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Өдрийг бууруулах"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Жилийг өсгөх"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Жил бууруулах"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Өмнөх сар"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Дараагийн сар"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Цуцлах"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Устгах"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Минут сонгоно уу"</string>
     <string name="select_day" msgid="7774759604701773332">"Сар болон өдрийг сонгоно уу"</string>
     <string name="select_year" msgid="7952052866994196170">"Жилийг сонгоно уу"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> сонгогдсон"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> устсан"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Энэ дэлгэцийг цуцлахын тулд Буцах болон Тойм-д зэрэг хүрч барина."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тогтоосныг суллахаас өмнө PIN асуух"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Батарей хадгалах функц нь таны төхөөрөмжийн цэнэгийг хадгалахын тулд гүйцэтгэлийг багасгаж, чичрэлтийг бууруулж, байршлын үйлчилгээнүүд болон бусад өгөгдлийн хэмжээг багасгадаг юм. И-мэйл, мессеж болон бусад синхрон хийдэг апликейшнүүд дараа дахин нээгдэх хүртлээ автоматаар шинэчлэлт хийхгүй.\n\nМөн батарей хадгалах функц нь таныг төхөөрөмжөө цэнэглэх үед автоматаар унтрах юм."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Таны уйтгартай байдал <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>-д дуусах хүртэл"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Сул зогсолт дуусах хүртэл"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 2fe3f37..b5fe8f8 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"रोमिंग बॅनर बंद"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"सेवा शोधत आहे"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"वाय-फाय कॉलिंग"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"बंद"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"वाय-फाय प्राधान्यकृत"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"सेल्युलर प्राधान्यकृत"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"केवळ वाय-फाय"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अग्रेषित केला नाही"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकंदांनंतर <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्‍यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"कॅमेरा वापरात असताना प्रक्षेपण सूचक LED अक्षम करा"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पूर्व-स्‍थापित सिस्‍टम अनुप्रयोगाला कॅमेरा वापर सूचक LED अक्षम करण्‍याची अनुमती देते."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"पूर्व-स्थापित सिस्टीम अनुप्रयोगास कॅमेरा सेवा सिस्टीम इव्हेंट पाठविण्यासाठी अनुमती देते."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"टॅब्लेट कायमचा अक्षम करा"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"टीव्ही कायमचा अक्षम करा"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"फोन कायमचा अक्षम करा"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA TV सेटअप थेट प्रारंभ करा"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA फोन सेटअप थेट प्रारंभ करा"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMA तरतूद प्रारंभ करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स CDMA तरतूद अनावश्यकपणे प्रारंभ करू शकतात."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"सिम कार्ड सेटअप प्रारंभ करा"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"सिम सक्रियकरण विनंत्या हाताळण्यासाठी अॅपला अनुमती देते. अॅप सक्रियकरण थेट करू शकतो किंवा दुसर्‍या अॅपला प्रतिनिधी नियुक्त करू शकतो."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"नियंत्रण स्थान अद्यतन सूचना"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"रेडिओवरील स्थान अद्यतन सूचना सक्षम/अक्षम करण्यासाठी अॅप ला अनुमती देते. सामान्य अॅप्सद्वारे वापरण्यासाठी नाही."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"चेकइन गुणधर्मांवर प्रवेश करा"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM प्रमाणपत्रे काढण्यासाठी अनुप्रयोगास अनुमती देते. सामान्य अॅप्स साठी कधीही आवश्यकता नसते."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"एका वाहक संदेशन सेवेसाठी प्रतिबद्ध"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"वाहक संदेशन सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"व्हॉइस परस्परसंवाद सेवेसह परस्परसंवाद करा"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"धारकास सध्‍या सक्रिय व्‍हॉइस परस्परसंवाद सेवेसह परस्परसंवाद करण्‍याची अनुमती देते. सामान्‍य अ‍ॅपसाठी कधीही आवश्‍यक नसते."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"संकेतशब्द नियम सेट करा"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक संकेतशब्द आणि पिन मध्ये अनुमती दिलेली लांबी आणि वर्ण नियंत्रित करा."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"स्क्रीन-अनलॉक प्रयत्नांचे परीक्षण करा"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"पॅकेज स्थापित करण्यायोग्य आहे हे सत्यापित करण्यासाठी अॅप ला अनुमती देते."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पॅकेज सत्यापकावर प्रतिबद्ध व्हा"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"पॅकेज सत्यापित करणार्‍यांच्या विनंत्या करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"हेतू फिल्टर सत्यापित करा"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"हेतू फिल्टर सत्यापित केले आहे किंवा नाही हे तपासण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"हेतू फिल्टर सत्यापनकर्त्यावर प्रतिबद्ध व्हा"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"हेतू फिल्टर सत्यापनकर्त्यांच्या विनंत्या करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यकता नसावी."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"क्रमांक पोर्टवर प्रवेश करा"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API वापरून क्रमांक पोर्टवर प्रवेश करण्यास होल्डरला अनुमती देते."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"सामग्री प्रदात्यांवर बाह्यरित्या प्रवेश करेल"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिवस कमी करा"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष वाढवा"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष कमी करा"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"मागील महिना"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"पुढील महिना"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द करा"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"हटवा"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"मिनिटे निवडा"</string>
     <string name="select_day" msgid="7774759604701773332">"महिना आणि दिवस निवडा"</string>
     <string name="select_year" msgid="7952052866994196170">"वर्ष निवडा"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> निवडले"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> हटविली"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ही स्क्रीन अनपिन करण्यासाठी, एकाच वेळी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्‍यापूर्वी पिन साठी विचारा"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"अनपिन करण्‍यापूर्वी अनलॉक नमुन्यासाठी विचारा"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"अनपिन करण्‍यापूर्वी संकेतशब्दासाठी विचारा"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"बॅटरीचे आयुष्य सुधारित करण्‍यात मदत करण्यासाठी, बॅटरी बचतकर्ता आपल्या डिव्हाइसचे कार्यप्रदर्शन कमी करतो आणि कंपन, स्थान सेवा आणि बराच पार्श्वभूमी डेटा मर्यादित करतो. संकालनावर अवलंबून असणारे ईमेल, संदेशन आणि इतर अ‍ॅप्स आपण उघडल्याशिवाय अद्यतनित होऊ शकत नाहीत.\n\nआपले डिव्हाइस चार्ज होत असते तेव्हा बॅटरी बचतकर्ता स्वयंचलितपणे बंद होतो."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"आपला कार्य न करण्याचा कालावधी <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> वाजता समाप्त होईपर्यंत"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"आपला कार्य न करण्याचा कालावधी समाप्त होईपर्यंत"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 132a7d4..883dde6 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Sepanduk Perayauan Dimatikan"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Mencari Perkhidmatan"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Panggilan Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Mati"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi diutamakan"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Selular diutamakan"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi sahaja"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Tidak dimajukan"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> selepas <xliff:g id="TIME_DELAY">{2}</xliff:g> saat"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"lumpuhkan LED penunjuk penghantaran semasa kamera sedang digunakan"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Membenarkan aplikasi sistem yang diprapasang untuk melumpuhkan LED penunjuk penggunaan kamera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Membenarkan aplikasi sistem yang diprapasang menghantar acara sistem perkhidmatan kamera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"melumpuhkan tablet secara kekal"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"lumpuhkan TV secara kekal"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"lumpuhkan telefon secara kekal"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"mulakan persediaan TV CDMA secara langsung"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"memulakan persediaan telefon CDMA secara langsung"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Membenarkan apl memulakan peruntukan CDMA. Apl hasad boleh memulakan peruntukan CDMA yang tidak perlu."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"mulakan persediaan kad SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Membenarkan apl mengendalikan permintaan pengaktifan SIM. Apl boleh melakukan pengaktifan secara langsung atau mewakilkan kepada apl lain."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kawal pemberitahuan kemas kini lokasi"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Membenarkan apl untuk mendayakan/melumpuhkan pemberitahuan kemas kini lokasi dari radio. Bukan untuk kegunaan apl biasa."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"akses sifat daftar masuk"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Membenarkan aplikasi mengalih keluar sijil DRM. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"terikat kepada perkhidmatan pemesejan pembawa"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Membenarkan pemegang terikat dengan antara muka peringkat tertinggi perkhidmatan pemesejan pembawa. Tidak sekali-kali diperlukan untuk apl biasa."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"berinteraksi dengan perkhidmatan interaksi suara"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Membenarkan pemegang berinteraksi dengan perkhidmatan interaksi suara aktif yang sedang aktif. Tidak sekali-kali diperlukan untuk apl biasa."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Tetapkan peraturan kata laluan"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Mengawal panjang dan aksara yang dibenarkan dalam kata laluan  dan PIN kunci skrin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Memantau percubaan buka kunci skrin"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Membenarkan apl untuk mengesahkan bahawa pakej boleh dipasang."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ikat kepada pengesah pakej"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"sahkan penapis hasrat"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Membenarkan apl untuk memeriksa sama ada penapis hasrat disahkan atau tidak."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"terikat kepada pengesah penapis hasrat"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Membenarkan pemegang membuat permintaan pengesah penapis hasrat. Tidak sekali-kali diperlukan untuk apl normal."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"akses pembekal kandungan secara luaran"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kurangkan hari"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tingkatkan tahun"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Kurangkan tahun"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Bulan sebelumnya"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Bulan seterusnya"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Batal"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Padam"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Pilih minit"</string>
     <string name="select_day" msgid="7774759604701773332">"Pilih bulan dan hari"</string>
     <string name="select_year" msgid="7952052866994196170">"Pilih tahun"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> dipilih"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> dipadamkan"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Kerja <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Untuk menyahsemat skrin ini, sentuh dan tahan Kembali serta Ikhtisar pada masa yang sama."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Minta corak buka kunci sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Minta kata laluan sebelum menyahsemat"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu memperbaik hayat bateri, penjimat bateri mengurangkan prestasi peranti anda dan menghadkan getaran, perkhidmatan lokasi dan kebanyakan data latar belakang. E-mel, pemesejan dan apl lain yang bergantung kepada penyegerakan mungkin tidak mengemas kini, melainkan anda membuka apl itu.\n\nPenjimat bateri dimatikan secara automatik semasa peranti anda sedang dicas."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Sehingga waktu gendala anda berakhir pada <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Sehingga waktu gendala anda berakhir"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 2e3f182..39fe3e1 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"ရုန်းမင်းစာတမ်းပိတ်ထားရန်"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"ဆားဗစ်အားရှာဖွေနေသည်"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"ဝိုင်ဖိုင် ခေါ်ဆိုမှု"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ပိတ်ထားရသည်"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"ဝိုင်ဖိုင်အား ပိုနှစ်သက်သော"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"ဆယ်လူလာအား ပိုနှစ်သက်သော"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"ကြိုးမဲ့အင်တာနက် သာလျှင်"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ထပ်ဆင့်မပို့နိုင်ပါ"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> နောက် <xliff:g id="TIME_DELAY">{2}</xliff:g> စက္ကန့်"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ထုတ်လွှင့်မှုပြ အချက်ပေး မီးအား ကင်မရာ သုံးနေစဉ် ပိတ်ရန်"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"ကြိုတင်သွင်းထားသော စစ်စတန် စနစ်တစ်ခုကို ကင်မရာ သုံးနေသော မီးအား ထိန်းချုပ်ခွင့်ပေးခြင်း"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"ကြိုတင်ထည့်သွင်းထားသည့် စနစ်အပလီကေးရှင်းကို စနစ်ဖြစ်ရပ်ကင်မရာ ဝန်ဆောင်မှုကို ပို့ခွင့်ပြုပါသည်။"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"တက်ပလက်ကို အမြဲတမ်း အလုပ်မလုပ်ရန်ပိတ်ခြင်း"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"တီဗွီအား အပြီးပိတ်ရန်"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ဖုန်းကို အမြဲတမ်း အလုပ်မလုပ်ရန်ပိတ်ခြင်း"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA TV ပြင်ဆင်သတ်မှတ်မှုအား တိုက်ရိုက်စတင်ရန်"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMAဖုန်း အစသတ်မှတ်ခြင်းကို တိုက်ရိုက်စတင်ရန်"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"appအား CDMA အတွက် စီမံလုပ်ကိုင်မှုကို စတင်ခွင့် ပြုသည်။ ကြံဖန် appများက မလိုအပ်ဘဲနှင့် CDMA အတွက် စီမံလုပ်ကိုင်မှုကို စတင်နိုင်ကြသည်။"</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM card စင် ဖွင့်လှစ်သတ်မှတ်ရန်"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"SIM စသုံးရန် တောင်းဆိုချက်များအား ကိုင်တွယ်ရန် app အား ခွင့်ပြုပါ။ App သည် စဖွင့်သုံးမှုအား တိုက်ရိုက် လုပ်ဆောင်မည် သို့မဟုတ် အခြား App အား ကိုယ်စားလုပ်စေမည်။"</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"တည်နေရာအဆင့်မြှင့်ခြင်းသတိပေးချက်အားထိန်းချုပ်ရန်"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"appအား ရေဒီယိုထံမှ တည်နေရာ မွမ်းမံမှု အကြောင်းကြားစာများကို ပိတ်/ဖွင့်ခွင့် ပြုသည်။ သာမန် appများ အသုံးပြုရန် မဟုတ်နိုင်ပါ။"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"ချက်ခ်အင်ဂုဏ်သတ္တိများအား ဝင်ရောက်ချိတ်ဆက်ခြင်း"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"အပလီကေးရှင်းအား DRM လက်မှတ်များကို ဖယ်ရှားခွင့် ပြုသည်။  သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"စာပို့စာယူ ဆက်သွယ်ရေးဝန်ဆောင်မှုတစ်ခုအား ပူးပေါင်းခွင့်ပြုရန်"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"စာပို့စာယူဆက်သွယ်ရေးဝန်ဆောင်မှုတစ်ခု၏ ထိပ်ဆုံးရှိအင်တာဖေ့စ်ဖြင့် ပူးပေါင်းရန် ပိုင်ရှင်အားခွင့်ပြုပါ။ ပုံမှန် app များအတွက် မလိုအပ်ပါ။"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"အသံအပြန်အလှန်စကားပြောခြင်း ဝန်ဆောင်မှုဖြင့် ချိတ်ဆက်ရန်"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"စွဲကိုင်ထားသူအား လက်ရှိပွင့်နေသည့် အသံအပြန်လှန်စကားပြောခြင်း ဝန်ဆောင်မှုကို ချိတ်ဆက်ရန် ခွင့်ပြုသည်။ သာမန်အပ်ဖ်များအတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"စကားဝှက်စည်းမျဥ်းကိုသတ်မှတ်ရန်"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"မျက်နှာပြင်သော့ခတ်သည့် စကားဝှက်များနှင့် PINများရှိ ခွင့်ပြုထားသည့် စာလုံးအရေအတွက်နှင့် အက္ခရာများအား ထိန်းချုပ်ရန်။"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"မော်နီတာမျက်နှာပြင်ဖွင့်ရန် ကြိုးစားခွင့်များ"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"appအား အထုပ် တစ်ခု၏ မတည်ငြိမ်မှုကို စိစစ်ခွင့် ပြုသည်။"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"package အတည်ပြုခြင်းနှင့် ပူးပေါင်းရန်"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"စွဲကိုင်ထားသူအား အထုပ်များအား စိစစ်ရေး တောင်းဆိုချက်များကို ပြုလုပ်ခွင့် ပေးသည်။ သာမန် appများ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"လိုအပ်သည့်စစ်ထုတ်ခြင်းကို အတည်ပြုမည်"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"လိုအပ်သည့်စစ်ထုတ်ခြင်း အတည်ပြုပြီးခြင်း ရှိမရှိ အပ်ဖ်အား စစ်ဆေးခွင့်ပြုမည်။"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"လိုအပ်သည့်စစ်ထုတ်ခြင်း အတည်ပြုကိရိယာဖြင့် ပေါင်းမည်"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"စွဲကိုင်ထားသူအား လိုအပ်အသည့်စစ်ထုတ်ခြင်း စိစစ်ရေး တောင်းဆိုချက်များကို ပြုလုပ်ခွင့် ပေးသည်။ သာမန် အပ်ဖ်များ အတွက် ဘယ်တော့မှ မလိုအပ်နိုင်ပါ။"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"အစဥ်လိုက်ပို့များကို ဝင်ရောက်ချိတ်ဆက်ခြင်း"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIအားအသုံးပြုကာ ကိုင်ဆောင်သူကို စီရီယာပို့မျာကို ဝင်ရောက်အသုံးပြုခြင်းအား ခွင့်ပြုသည်။"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"အချက်အလက်များ ပံ့ပိုသူများအား အပြင်ဖက်မှ ရယူခြင်း"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ရက် လျှော့ရန်"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"ခုနှစ် တိုးရန်"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ခုနှစ် လျှော့ရန်"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"ပြီးခဲ့သော လ"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"လာမည့် လ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Altခလုတ်"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ပယ်ဖျက်ရန်ခလုတ်"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ဖျက်ရန်ခလုတ်"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"မိနစ်များ ရွေးပါ"</string>
     <string name="select_day" msgid="7774759604701773332">"လ နှင့် ရက် ရွေးပါ"</string>
     <string name="select_year" msgid="7952052866994196170">"ခုနှစ်ကို ရွေးပါ"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ခုရွေးချယ်ထားပြီး"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> ကို ဖျက်ပြီးပါပြီ"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"အလုပ် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ဒီမျက်နှာပြင် ပင်ထိုးမှုကို ဖြုတ်ရန်၊ နောက်သို့ နှင့် ခြုံကြည့်မှု ခလုတ်များကို တစ်ချိန်တည်း ထိကိုင်ထားပါ။"</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ပင်မဖြုတ်မီမှာ PIN ကို မေးကြည့်ရန်"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ပင်မဖြုတ်မီမှာ သော့ဖွင့် ရေးဆွဲမှုပုံစံကို မေးကြည့်ရန်"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ပင်မဖြုတ်မီမှာ စကားဝှက်ကို မေးကြည့်ရန်"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ဘက်ထရီသက်တမ်း ကြာရှည်ခံရန်၊ ဘက်ထရီအားထိန်းသည် သင့်ကိရိယာ၏ ဆောင်ရွက်ချက်ကို  လျှော့ပေးပြီး တုန်ခါမှု၊ တည်နေရာဝန်ဆောင်မှုများနှင့်၊ နောက်ခံဒေတာအများစုကို ကန့်သတ်ပေး၏။ စင့်လုပ်ပေးရလေ့ရှိသည့် အီးမေး၊ စာပို့ခြင်းနှင့်၊ အခြားအပလီကေးရှင်းများကို ၎င်းတို့အား သင် ဖွင့်မှသာ အဆင့်မြှင့်မွမ်းမံမည်ဖြစ်၏။ \n\n ကိရိယာအား အားသွင်းနေစဉ် ဘက်ထရီအားထိန်းအား အလိုအလျောက် ပိတ်ထားသည်။"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"သင်၏ စက်ရပ်ချိန် <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> မှာ ပြီးဆုံးသည့် အထိ။"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"သင့်ကျချိန်အဆုံးအထိ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index de3cae4..7abcfaa 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roaming-banner av"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Leter etter tjeneste"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-anrop"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Ikke viderekoblet"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> etter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"deaktiver LED-lyset for indikering av overføring når kameraet er i bruk"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Tillater at forhåndsinnstallerte systemapper deaktiverer LED-indikatoren for kamerabruk."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Gjør at forhåndsinstallerte systemapper kan sende systemhandlinger for kameratjenester."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"deaktivere nettbrettet permanent"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"deaktiver TV-en permanent"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"deaktivere telefonen permanent"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"start CDMA-TV-konfigurering"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"begynne CDMA-telefonoppsett direkte"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Lar appen starte CDMA-oppsett. Ondsinnede apper kan bruke dette til å starte CDMA-oppsett uten grunn."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrollere varsling for plasseringsendring"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Lar appen aktivere og deaktivere varsler om posisjonsoppdatering fra radioen. Ikke beregnet på vanlige apper."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"bruke innsjekking"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Gir en app tillatelse til å fjerne sertifikater for digital rettighetsadministrasjon. Skal ikke være nødvendig for vanlige apper."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bind til en operatørmeldingstjeneste"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Tillater at innehaveren binder seg til det øverste nivået av grensesnittet til en operatørtjeneste. Dette skal aldri være nødvendig for vanlige apper."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"samhandle med tjenesten for talehandlinger"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Tillater eieren å samhandle med den aktive tjenesten for talehandlinger. Dette skal aldri være nødvendig for vanlige apper."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angi passordregler"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollerer tillatt lengde og tillatte tegn i passord og PIN-koder for opplåsing av skjermen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåk forsøk på opplåsing av skjerm"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lar appen bekrefte om en pakke kan installeres."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en pakkeverifikator"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"bekreft intensjonsfilter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Gjør at appen kan sjekke om et bestemt intensjonsfilter er bekreftet eller ikke."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"knytt til en verifikator for intensjonsfiltre"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Lar innehaveren sende forespørsler om verifikatorer for intensjonsfiltre. Skal aldri være nødvendig for vanlige apper."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"bruke serieporter"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"gå til innholdsleverandører eksternt"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduser dager"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Øk år"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduser år"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Forrige måned"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Neste måned"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Slett"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Angi minutter"</string>
     <string name="select_day" msgid="7774759604701773332">"Velg måneden og dagen"</string>
     <string name="select_year" msgid="7952052866994196170">"Velg året"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> er valgt"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> er slettet"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Jobb-<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Hvis du vil avslutte én-appsmodusen for denne skjermen, trykker og holder du på Tilbake og Oversikt samtidig."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Krev PIN-kode for å løsne apper"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Krev bruk av opplåsningsmønster for å løsne apper"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Krev passord for å løsne apper"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"For å bidra til å forbedre batterilevetiden reduserer batterispareren ytelsen til enheten din og begrenser vibrering, posisjonstjenester og mesteparten av bakgrunnsdataene. E-post, sending av meldinger og andre apper som er avhengig av synkronisering oppdateres kanskje ikke med mindre du åpner dem.\n\nBatterisparing slås av automatisk når enheten lader."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Til hviletiden din ender kl. <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Inntil nedetiden din er over"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 1b8180a..dcb1b31 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"रोमिङ ब्यानर बन्द छ"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"सेवाको खोजी गर्दै…"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi कलिङ"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"बन्द गर्नुहोस्"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi मनपराइयो"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"सेलुलर मनपराइयो"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi मात्र"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: अगाडि पठाइएको छैन"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> पछि <xliff:g id="TIME_DELAY">{2}</xliff:g> सेकेन्ड"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"क्यामेरा प्रयोगमा हुँदा सूचक LED प्रसारण असक्षम गर्नुहोस्"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"पूर्व-स्थापित प्रणाली अनुप्रयोगलाई क्यामेरा उपयोग सूचक LED अक्षम गर्न अनुमति दिन्छ।"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"एउटा पूर्व-स्थापित प्रणाली अनुप्रयोगलाई क्यामेरा सेवा प्रणाली घटनाहरू पठाउन अनुमति दिन्छ।"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"स्थायी रूपमा ट्याब्लेट असक्षम पार्नुहोस्"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"स्थायी रूपमा TV अक्षम गर्नुहोस्"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"फोनलाई स्थायी रूपमा असक्षम पार्नहोस्"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"प्रत्यक्ष CDMA TV सेटअप सुरु गर्नुहोस्"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA फोन सेटअप सिधै सुरु गर्नुहोस्"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"अनुप्रयोगलाई CDMA प्रावधान सुरu गर्न अनुमति दिन्छ। खराब अनुप्रयोगहरूले अनावश्यक रूपमा CDMA प्रावधान सुरु गर्न सक्छन्।"</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM कार्ड सेटअप सुरु गर्नुहोस्"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"अनुप्रयोगलाई SIM सक्रियता अनुरोध सञ्चालन गर्न अनुमति दिन्छ। अनुप्रयोगले सक्रियता सीधै सम्पादन गर्न सक्छ वा अन्य अनुप्रयोगलाई प्रत्यायोजन गर्न सक्छ।"</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"स्थान अपडेट सूचनाहरू नियन्त्रण गर्नुहोस्"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"रेडियोबाट स्थान अद्यावधिक सूचनाहरूलाई सक्षम/असक्षम गर्न अनुप्रयोगलाई अनुमति दिन्छ। सामान्य अनुप्रयोगहरूबाट प्रयोग नहुने।"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"परीक्षण विशेषताहरू पहुँच गर्नुहोस्"</string>
@@ -753,7 +762,7 @@
     <string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"औंला निकै छिटो सारियो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
     <string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"औंला निकै ढिला सारियो। कृपया फेरि प्रयास गर्नुहोस्।"</string>
   <string-array name="fingerprint_acquired_vendor">
-    <item msgid="2892952818207766996">"उत्पादक-निर्दिष्ट अधिग्रहण त्रुटि सन्देश 0"</item>
+    <item msgid="2892952818207766996">"विक्रेता-निर्दिष्ट अधिग्रहण त्रुटि सन्देश 0"</item>
   </string-array>
     <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"प्रसोधन गर्न असमर्थ। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"हार्डवेयर उपलब्ध छैन।"</string>
@@ -761,7 +770,7 @@
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
     <string name="fingerprint_error_vendor" msgid="3175724710791609491">"औँठाछापको समय सकिएको छ। फेरि प्रयास गर्नुहोस्।"</string>
   <string-array name="fingerprint_error_vendor">
-    <item msgid="5804600450373644614">"उत्पादक-निर्दिष्ट त्रुटि सन्देश।"</item>
+    <item msgid="5804600450373644614">"विक्रेता-निर्दिष्ट त्रुटि सन्देश।"</item>
   </string-array>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"अनुप्रयोगलाई खाताको लागि सिङ्क सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको अनुप्रयोग खातासँग सिङ्क भएको नभएको निर्धारण गर्न सक्दछ।"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM प्रमाणपत्रहरू हटाउन अनुप्रयोगलाई अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"वाहक मेसेजिङ सेवामा आबद्ध हुनुहोस्"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"धारकलाई वाहक मेसेजिङ सेवाको उच्च-स्तरको इन्टरफेसमा आबद्ध हुन अनुमति दिनुहोस्। सामान्य एपहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"आवाज अन्तरक्रिया सेवासँग अन्तरक्रिया गर्नुहोस्"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"होल्डरलाई हालैको सक्रिय आवाज अन्तरक्रिया सेवासँग अन्तरक्रिया गर्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियमहरू मिलाउनुहोस्"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रिन लक पासवर्ड र PIN हरूमा अनुमति दिइएको लम्बाइ र वर्णहरूको नियन्त्रण गर्नुहोस्।"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"मोनिटर स्क्रिन-अनलक प्रयत्नहरू"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"प्याकेज स्थापना योग्य छ कि भनेर रुजु गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"एउटा प्याकेज रुजुकर्तामा बाँध्नुहोस्"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"होल्डरलाई प्याकेज प्रमाणितकर्ताहरूको अनुरोधहरू बनाउन अनुमति दिन्छ। सामान्य अनुप्रयोगहरूलाई कहिले पनि आवश्यक नपर्न सक्दछ।"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"उद्देश्य फिल्टर प्रमाणिकरण गर्नुहोस्"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"एउटा उद्देश्य फिल्टर प्रमाणित भएको छ वा छैन भन्ने जाँच्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"उद्देश्य फिल्टर प्रमाणिकरणकर्ता बाँध्नुहोस्"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"होल्डरलाई उद्देश्य फिल्टर प्रमाणिकरणकर्ताहरूका अनुरोध गर्न अनुमति दिन्छ। सामान्य अनुप्रयोगहरूको लागि कहिल्यै आवश्यकता पर्दैन।"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"पहुँच सिरियल पोर्टहरू"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"होल्डरलाई SerialManager API प्रयोग गरेर सिरियल पोर्टहरू पहुँच गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"विषयसूची प्रदातालाई बाह्य रूपमा पहुँच गर्नुहोस्"</string>
@@ -1567,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"दिन घटाउनुहोस्"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"वर्ष बढाउनुहोस्"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"वर्ष घटाउनुहोस्"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"अघिल्लो महिना"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"अर्को महिना"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"रद्द गर्नुहोस्"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"मेट्नुहोस्"</string>
@@ -1819,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"मिनेट चयन गर्नुहोस्"</string>
     <string name="select_day" msgid="7774759604701773332">"महिना र दिन चयन गर्नुहोस्"</string>
     <string name="select_year" msgid="7952052866994196170">"वर्ष चयन गर्नुहोस्"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> चयन गरियो"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> हटाइयो"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"यस पर्दालाई अनपिन गर्न एकै समय फिर्ता र सारांशलाई छोई पक्डिनुहोस्।"</string>
@@ -1830,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"पिन निकाल्नुअघि PIN सोध्नुहोस्"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"पिन निकाल्नुअघि खोल्ने रूपरेखा सोध्नुहोस्"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"ब्याट्रीको आयु सुधार्न, ब्याट्री रक्षकले तपाईँको यन्त्रको कार्यसम्पादन घटाउँछ र भाइब्रेसन, स्थान सेवा र बहुसंख्यक पृष्ठभूमि डेटा सीमित गर्दछ। इमेल, सन्देश, र अन्य अनुप्रयोगहरू जुन सिङ्कमा भर पर्छन् अद्यावधिक नहुन सक्छन् जबसम्म तपाईँ तिनीहरूलाई खोल्नुहुन्न\n\n ब्याट्री रक्षक स्वत: निस्कृय हुन्छ जब तपाईँको यन्त्र चार्ज हुँदै हुन्छ।"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"तपाईँको <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> डाउनटाइम समाप्त हुँदा सम्म"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"तपाईँको डाउनटाइम समाप्त नभए सम्म"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 425cb3a..8a0b056 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roamingbanner uit"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Service zoeken"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Bellen via wifi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: niet doorgeschakeld"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> na <xliff:g id="TIME_DELAY">{2}</xliff:g> seconden"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder uw bevestiging."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"indicatielampje uitschakelen wanneer camera wordt gebruikt"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Staat toe dat een vooraf geïnstalleerde systeemapp het indicatielampje voor cameragebruik uitschakelt."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Hiermee kan een vooraf geïnstalleerde systeemapp systeemgebeurtenissen verzenden naar de cameraservice."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"tablet permanent uitschakelen"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"tv permanent uitschakelen"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"telefoon permanent uitschakelen"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"tv-instelling via CDMA rechtstreeks starten"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"meteen starten met CDMA-telefooninstelling"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Hiermee kan de app starten met CDMA-provisioning. Schadelijke apps kunnen de CDMA-provisioning onnodig starten."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"meldingen over locatie-updates beheren"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Hiermee kan de app locatie-updatemeldingen van de radio in- of uitschakelen. Niet voor gebruik door normale apps."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"toegang tot checkin-eigenschappen"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Toestaan dat een app DRM-certificaten verwijdert. Nooit vereist voor normale apps."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"binden aan de berichtenservice van een provider"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Hiermee wordt de houder toegestaan te binden aan de berichteninterface van een provider. Nooit vereist voor normale apps."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"de service voor spraakinteractie gebruiken"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Hiermee kan de houder de momenteel actieve service voor spraakinteractie gebruiken. Nooit vereist voor normale apps."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"De lengte en het aantal tekens beheren die zijn toegestaan in wachtwoorden en pincodes voor schermvergrendeling."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Hiermee kan de app controleren of een pakket kan worden geïnstalleerd."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"koppelen aan pakketcontroleprogramma"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"intentiefilter verifiëren"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Hiermee kan de app controleren of een intentiefilter is geverifieerd."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"verbinden aan intentiefilterverificatie"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Hiermee kan de houder verzoeken indienen voor verificatie van intentiefilters. Nooit vereist voor normale apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externe toegang tot inhoudsproviders"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Lagere waarde voor dag"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Hogere waarde voor jaar"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Lagere waarde voor jaar"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Vorige maand"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Volgende maand"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Annuleren"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Minuten selecteren"</string>
     <string name="select_day" msgid="7774759604701773332">"Maand en dag selecteren"</string>
     <string name="select_year" msgid="7952052866994196170">"Jaar selecteren"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> geselecteerd"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> verwijderd"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Werk <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Blijf \'Terug\' en \'Overzicht\' tegelijk aanraken om dit scherm los te maken."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Vragen om pincode voordat items worden losgemaakt"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Vragen om ontgrendelingspatroon voordat items worden losgemaakt"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Vragen om wachtwoord voordat items worden losgemaakt"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Accubesparing beperkt de prestaties van uw apparaat, de trilstand, locatieservices en de meeste achtergrondgegevens om de gebruiksduur van de accu te verlengen.\n\nAccubesparing wordt automatisch uitgeschakeld terwijl uw apparaat wordt opgeladen."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Totdat uw downtime eindigt om <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Tot uw downtime afloopt"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b10ea37..2066d4e 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -126,9 +126,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Baner roamingu wyłączony"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Wyszukiwanie usługi"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Połączenia przez Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: nieprzekierowane"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> sekundach"</string>
@@ -587,6 +597,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"wyłącz wskaźnik LED transmisji, gdy aparat jest w użyciu"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Zezwala wstępnie zainstalowanej aplikacji systemowej na wyłączenie wskaźnika LED użycia kamery."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Zezwala wstępnie zainstalowanej aplikacji systemowej na wysyłanie zdarzeń systemowych obsługi aparatu."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trwałe wyłączenie tabletu"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"trwałe wyłączenie telewizora"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"wyłączenie telefonu na stałe"</string>
@@ -635,6 +646,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"bezpośrednie uruchamianie konfiguracji CDMA na telewizorze"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"Bezpośrednio rozpocznij konfigurację telefonu CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Pozwala aplikacji na rozpoczęcie obsługi CDMA. Złośliwe aplikacje mogą bez potrzeby rozpoczynać obsługę CDMA."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kontrolowanie powiadomień o aktualizacjach lokalizacji"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Pozwala aplikacji na włączanie/wyłączanie powiadomień o aktualizacji lokalizacji pobieranych z radia. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"dostęp do właściwości usługi rezerwacji"</string>
@@ -841,6 +856,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Zezwala aplikacji na usuwanie certyfikatów DRM. Nie powinno być nigdy potrzebne w zwykłych aplikacjach."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"powiąż z usługą przesyłania wiadomości przez operatora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Zezwala posiadaczowi na tworzenie powiązania z interfejsem najwyższego poziomu w usłudze przesyłania wiadomości przez operatora. Nie powinno być nigdy potrzebne dla zwykłych aplikacji."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"korzystanie z usługi interakcji głosowej"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Pozwala na korzystanie z aktualnie włączonej usługi interakcji głosowej. Nie powinno być nigdy potrzebne w zwykłych aplikacjach."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Określ reguły hasła"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolowanie długości haseł blokady ekranu i kodów PIN oraz dozwolonych w nich znaków."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitoruj próby odblokowania ekranu"</string>
@@ -1138,6 +1155,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pozwala aplikacji na zweryfikowanie, czy pakiet można zainstalować."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"powiązanie z weryfikatorem pakietów"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"weryfikacja filtru intencji"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Zezwala aplikacji na sprawdzenie, czy filtr intencji został zweryfikowany."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"tworzenie powiązania z weryfikacją filtru intencji"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Zezwala na wysyłanie żądań weryfikacji filtrów intencji. Nieprzeznaczone dla zwykłych aplikacji."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Dostęp do dostawców treści z zewnątrz"</string>
@@ -1577,6 +1598,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Zmień dzień na wcześniejszy"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Zmień rok na późniejszy"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Zmień rok na wcześniejszy"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Poprzedni miesiąc"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Następny miesiąc"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anuluj"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1831,7 +1854,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Wybierz minuty"</string>
     <string name="select_day" msgid="7774759604701773332">"Wybierz miesiąc i dzień"</string>
     <string name="select_year" msgid="7952052866994196170">"Wybierz rok"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Wybrałeś <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> usunięte"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (praca)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Aby odpiąć ten ekran, naciśnij i przytrzymaj jednocześnie Wstecz i Przegląd."</string>
@@ -1842,6 +1864,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Aby odpiąć, poproś o PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Aby odpiąć, poproś o wzór odblokowania"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Aby odpiąć, poproś o hasło"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Aby wydłużyć czas pracy baterii, Oszczędzanie baterii ogranicza aktywność urządzenia, w tym wibracje, usługi lokalizacyjne i przetwarzanie większości danych w tle. Poczta, czat i inne synchronizowane aplikacje mogą nie aktualizować swojej zawartości, dopóki ich nie otworzysz.\n\nOszczędzanie baterii wyłącza się automatycznie podczas ładowania urządzenia."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Do zakończenia przestoju o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Do zakończenia wyłączenia"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 4f1187c..ff5c5a0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Faixa de Roaming desativada"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"A procurar Serviço"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Chamadas Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não reencaminhado"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desativar LED indicador de transmissão com a câmara em utilização"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que uma aplicação de sistema pré-instalada desative o LED indicador de utilização da câmara."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permite que uma aplicação de sistema pré-instalada envie eventos do sistema para o serviço da câmara."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desativar tablet de forma permanente"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"desativar a TV permanentemente"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"desativar telefone de forma permanente"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"iniciar diretamente a configuração da TV CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar diretamente a configuração do telefone CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite que a aplicação inicie a administração CDMA. As aplicações maliciosas podem iniciar a administração CDMA desnecessariamente."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar notificações de actualização de localização"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite que a aplicação ative/desative as notificações de atualização de localização do rádio. Não se destina a utilização por aplicações normais."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"aceder a propriedades de verificação"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite que uma aplicação remova certificados DRM. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ligar ao serviço de mensagens de um operador"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite ao titular ligar à interface de nível superior do serviço de mensagens de um operador. Nunca deve ser necessário para aplicações normais."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interagir com serviço de interação por voz"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permite ao proprietário interagir com o serviço de interação por voz ativo no momento. Nunca deve ser necessário para aplicações normais."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras de palavra-passe"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controlar o comprimento e os carateres permitidos nos PINs e nas palavras-passe do bloqueio de ecrã."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizar tentativas de desbloqueio do ecrã"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que a aplicação verifique se um pacote é instalável."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacotes"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"validar filtro de intenções"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que uma aplicação verifique se um filtro de intenções está ou não validado."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"vincular a um verif. de filtros intenç."</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite ao titular solicitar verificadores de filtros de intenções. Nunca deve ser necessário para aplicações normais."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"aceder a fornecedores de conteúdos externamente"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Diminuir dia"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Diminuir ano"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mês anterior"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mês seguinte"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Selecionar minutos"</string>
     <string name="select_day" msgid="7774759604701773332">"Selecionar mês e dia"</string>
     <string name="select_year" msgid="7952052866994196170">"Selecionar ano"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selecionado"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> eliminado"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de trabalho"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para soltar este ecrã, toque sem soltar em Retroceder e Visão geral em simultâneo."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de soltar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir sequência de desbloqueio antes de soltar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir palavra-passe antes de soltar"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a autonomia da bateria, a poupança de bateria reduz o desempenho do seu dispositivo e limita a vibração, os serviços de localização e a maioria dos dados em segundo plano. O email, as mensagens e outras aplicações que dependem da sincronização não podem ser atualizados exceto se os abrir.\n\nA poupança de bateria desliga-se automaticamente quando o dispositivo está a carregar."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Até o período de inatividade terminar às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Até terminar o período de inatividade"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6f68f06..3af2d90 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner de roaming desativado"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Pesquisando serviço"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Chamadas por Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Desativado"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi preferido"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Celular preferido"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Somente Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Não encaminhado"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> após <xliff:g id="TIME_DELAY">{2}</xliff:g> segundos"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"desativar a transmissão do LED indicador quando a câmera estiver em uso"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite que um app do sistema pré-instalado desative o LED indicador de uso da câmera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permite que um app pré-instalado do sistema envie os eventos do sistema de serviço de câmera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"desativar permanentemente o tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"desativar TV permanentemente"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"desativar permanentemente o telefone"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"iniciar diretamente a configuração CDMA da TV"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"iniciar a configuração do telefone CDMA diretamente"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite que o app inicie o provisionamento CDMA. Apps maliciosos podem iniciar o provisionamento CDMA de maneira desnecessária."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"iniciar a configuração do cartão SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Permite que o app controle solicitações de ativação de SIM. O app pode realizar a ativação diretamente ou pode delegá-la a outro app."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar as notificações de atualização do local"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite que o app ative/desative as notificações de atualização de local do rádio. Não deve ser usado em apps normais."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"acessar propriedades de verificação"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite que um app remova certificados de DRM. Não deve ser necessário para apps comuns."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"vincular a um serviço de mensagens de operadora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite que o proprietário use a interface de nível superior de um serviço de mensagens de operadora. Não deve ser necessária para apps comuns."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interagir com o serviço de interação de voz"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permite que o proprietário interaja com o serviço de interação de voz ativo. Não deve ser necessário para apps comuns."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Definir regras para senha"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Controla o tamanho e os caracteres permitidos nos PINs e nas senhas do bloqueio de tela."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorar tentativas de desbloqueio da tela"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que o app verifique se um pacote pode ser instalado."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacote"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para apps normais."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verificar filtro de intenção"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite que o app verifique se um filtro de intenção foi confirmado ou não."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"usar verificador de filtro de intenção"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite que o titular solicite verificadores de filtro de intenção. Nunca é necessário para apps normais."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"acessar fornec. de conteúdo externamente"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Diminuir dia"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Aumentar ano"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Diminuir ano"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mês passado"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Próximo mês"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Cancelar"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Excluir"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Selecione os minutos"</string>
     <string name="select_day" msgid="7774759604701773332">"Selecione o mês e o dia"</string>
     <string name="select_year" msgid="7952052866994196170">"Selecione o ano"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selecionado"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> excluído"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Trabalho: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Para liberar esta tela, toque e mantenha pressionados \"Voltar\" e \"Visão geral\" ao mesmo tempo."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pedir PIN antes de liberar"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pedir senha antes de liberar"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Para ajudar a melhorar a duração da bateria, o economizador de bateria reduz o desempenho e os limites de vibração do dispositivo, os serviços de localização e a maioria dos dados de segundo plano. E-mail, mensagens e outros aplicativos que dependem de sincronização não podem ser atualizados, a não ser que você os abra.\n\nO economizador de bateria é desligado automaticamente quando o dispositivo está sendo carregado."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Até o período de inatividade terminar às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Até que seu tempo de inatividade termine"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index dc29c19..1c28cf8 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -125,9 +125,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner roaming dezactivat"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Se caută serviciul"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Apelare prin Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionată"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g> (de) secunde"</string>
@@ -586,6 +596,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"dezactivează ledul care indică când este utilizată camera foto"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Permite unei aplicații de sistem preinstalate să dezactiveze ledul care indică utilizarea camerei foto."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Permite unei aplicații de sistem preinstalate să trimită evenimentele de sistem către serviciul Cameră foto."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"dezactivarea permanentă a computerului tablet PC"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"dezactivează definitiv televizorul"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"dezactivare permanentă a telefonului"</string>
@@ -634,6 +645,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"pornește direct configurarea televizorului pentru CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"pornire directă a configuraţiei CDMA a telefonului"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Permite aplicației să pornească asigurarea accesului la CDMA. Aplicaţiile rău intenţionate pot să pornească asigurarea accesului la CDMA, fără ca aceasta să fie necesară."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"controlare notificări de actualizare a locaţiei"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Permite aplicației să activeze/dezactiveze notificările privind actualizarea locaţiei primite de la radio. Nu se utilizează de aplicațiile obişnuite."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"accesare proprietăţi checkin"</string>
@@ -840,6 +855,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Permite unei aplicații să elimine certificatele DRM. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"se conectează la un serviciu de mesagerie oferit de operator"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Permite aplicației să se conecteze la interfața de nivel superior a unui serviciu de mesagerie oferit de operator. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interacționează cu serviciul de interacțiune vocală"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Permite aplicației să interacționeze cu serviciul activ de interacțiune vocală. Nu ar trebui să fie necesară niciodată pentru aplicațiile obișnuite."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Setaţi reguli pentru parolă"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Stabiliți lungimea și tipul de caractere permise pentru parolele și codurile PIN de blocare a ecranului."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Monitorizaţi încercările de deblocare a ecranului"</string>
@@ -1137,6 +1154,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite aplicației să verifice dacă un pachet poate fi instalat."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"conectare la un verificator de pachete"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicațiile obişnuite."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifică filtrul de intenții"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Permite aplicației să afle dacă filtrul de intenții este verificat sau nu."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"se conectează la verificator de filtre de intenții"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Permite aplicației să facă solicitări pentru verificatorii filtrelor de intenții. Nu ar trebui să fie niciodată necesară pentru aplicațiile obișnuite."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"accesaţi furniz. de conţin. din exterior"</string>
@@ -1569,6 +1590,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduceţi valoarea pentru zi"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creşteţi valoarea pentru an"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduceţi valoarea pentru an"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Luna trecută"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Luna viitoare"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Anulați"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Ștergeţi"</string>
@@ -1822,7 +1845,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Selectați minutele"</string>
     <string name="select_day" msgid="7774759604701773332">"Selectați luna și ziua"</string>
     <string name="select_year" msgid="7952052866994196170">"Selectați anul"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> selectat"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> a fost șters"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> de serviciu"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Pentru a anula fixarea pe ecran, apăsați lung, simultan, pe Înapoi și pe Vizualizare generală."</string>
@@ -1833,6 +1855,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Solicită codul PIN înainte de a anula fixarea"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Solicită modelul pentru deblocare înainte de a anula fixarea"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Solicită parola înainte de a anula fixarea"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Pentru a îmbunătăți autonomia bateriei, funcția de economisire a energiei reduce performanțele dispozitivului și limitează vibrațiile, serviciile de localizare și majoritatea datelor de fundal. Este posibil ca e-mailurile, mesageria și alte aplicații care depind de sincronizare să nu se actualizeze dacă nu le deschideți.\n\nFuncția de economisire a energiei se dezactivează automat când dispozitivul se încarcă."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Până când inactivitatea dvs. se încheie la <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Până la finalizarea perioadei de inactivitate"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index eb3b74a..9642ef8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -126,9 +126,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Баннер роуминга выключен"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Поиск службы"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Звонки по Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переадресовано"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> через <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
@@ -587,6 +597,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Отключать светодиодный индикатор во время использования камеры"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Предустановленное системное приложение сможет отключать светодиодный индикатор использования камеры."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Предустановленное системное приложение сможет передавать системные события службы камеры."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"Выключение планшета"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"навсегда отключать телевизор"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"Отключение телефона"</string>
@@ -635,6 +646,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"выполнять настройку CDMA на телевизоре"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"Прямой запуск настройки телефона CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Приложение сможет запускать настройку CDMA. Вредоносные программы также смогут делать это без необходимости."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"Управление уведомлениями об обновлении местоположения"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Приложение сможет включать и отключать уведомления об обновлении местоположения на основе данных приемопередачика. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"Доступ к регистрационным данным"</string>
@@ -755,7 +770,7 @@
     <string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"Вы слишком быстро убрали палец. Повторите попытку."</string>
     <string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"Вы слишком долго удерживали палец. Повторите попытку."</string>
   <string-array name="fingerprint_acquired_vendor">
-    <item msgid="2892952818207766996">"Сообщение продавца об ошибке при сканировании отпечатка (0)"</item>
+    <item msgid="2892952818207766996">"Сообщение об ошибке при сканировании отпечатка (0)"</item>
   </string-array>
     <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"Не удалось распознать отпечаток. Повторите попытку."</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"Сканер недоступен."</string>
@@ -763,7 +778,7 @@
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Превышено время ожидания. Повторите попытку."</string>
     <string name="fingerprint_error_vendor" msgid="3175724710791609491">"Превышено время ожидания. Повторите попытку."</string>
   <string-array name="fingerprint_error_vendor">
-    <item msgid="5804600450373644614">"Сообщение продавца об ошибке."</item>
+    <item msgid="5804600450373644614">"Сообщение об ошибке."</item>
   </string-array>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"Просмотр настроек синхронизации"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
@@ -841,6 +856,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Удаление сертификатов DRM. Большинству приложений это разрешение не требуется."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Подключение к службе обмена сообщениями"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Подключение к базовому интерфейсу службы обмена сообщениями, предоставляемой оператором связи. Это разрешение обычно используется только специальными приложениями."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"работа со службой голосового взаимодействия"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Приложение сможет работать с активной службой голосового взаимодействия. Это разрешение не используется обычными приложениями."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Правила выбора паролей"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролировать длину и символы при вводе пароля и PIN-кода."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Отслеживать попытки снятия блокировки экрана"</string>
@@ -1138,6 +1155,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Приложение сможет проверять возможность установки пакетов."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Подключение к верификаторам пакетов"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"Проверка фильтров намерений"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Приложение сможет узнавать, проверен ли фильтр намерений."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"Подключение к проверке фильтров намерений"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Приложение сможет запрашивать проверку фильтров намерений. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"Доступ к последовательным портам"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"Доступ к контенту без приложения"</string>
@@ -1577,6 +1598,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"На год вперед"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На год назад"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Прошлый месяц"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Следующий месяц"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Клавиша ALT"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Отмена"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Клавиша удаления"</string>
@@ -1831,7 +1854,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Выберите минуты"</string>
     <string name="select_day" msgid="7774759604701773332">"Выберите месяц и число"</string>
     <string name="select_year" msgid="7952052866994196170">"Выберите год"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Выбран элемент <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Цифра <xliff:g id="KEY">%1$s</xliff:g> удалена"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Рабочий <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Чтобы открепить экран, нажмите и удерживайте кнопки \"Назад\" и \"Обзор\" одновременно."</string>
@@ -1842,6 +1864,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запрашивать PIN-код для отключения блокировки"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запрашивать графический ключ для отключения блокировки"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запрашивать пароль для отключения блокировки"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Чтобы продлить время работы устройства от батареи, в режиме энергосбережения снижается производительность, а также ограничивается использование вибрации, геолокации и фоновой передачи данных. Данные, требующие синхронизации, могут обновляться только когда вы откроете приложение.\n\nРежим энергосбережения автоматически отключается во время зарядки устройства."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"До отключения режима (в <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До отключения режима"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 6d8b6df..cc498b2 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"රෝමිං බැනරය අක්‍රියයි"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"සේවාව සඳහා සොයමින්"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi ඇමතීම"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ක්‍රියාවිරහිතයි"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi වඩා කැමතියි"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"සෙලියුලර් වඩා කැමතියි"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi පමණයි"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ඉදිරියට නොයවන ලදි"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: තත්පර <xliff:g id="TIME_DELAY">{2}</xliff:g> ට පසුව <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"කැමරාව භාවිතයේදී LED දර්ශක සම්ප්‍රේෂණය අබල කරන්න"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"කැමරා භාවිතය පිළිබඳ LED දර්ශකය අක්‍රිය කිරීමට, කලින් පිහිටුවා ඇති පද්ධති යෙදුමට අවසර දෙන්න."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"කැමරා සේවා පද්ධති සිද්ධි යැවීමට, පූර්ව-ස්ථාපිත පද්ධති යෙදුමකට අවසර දෙයි."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ටැබ්ලටය ස්ථිරවම අබල කිරීම"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"රූපවාහිනිය ස්ථිරවම අබල කරන්න"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"දුරකථනය ස්ථිරව අබල කිරීම"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"කෙළින්ම CDMA රුපවාහිනී ස්ථාපනය ආරම්භ කරන්න"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA දුරකථන පිහිටුම සෘජුව ඇරඹීම"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"යෙදුමට CDMA ප්‍රතිපාදන ආරම්භ කිරීමට ඉඩදෙන්න. අනිෂ්ට යෙදුම් අනවශ්‍ය ලෙස CDMA ප්‍රතිපාදන ආරම්භ කළ හැක."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM කාඩ්පත පිහිටුවීම අරඹන්න"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"යෙදුමට SIM සක්‍රිය කිරීම් ඉල්ලීම් හැසිරවීමට ඉඩ දෙයි. යෙදුම සෘජුවම සක්‍රිය කිරීම සිදු කිරීමට හෝ වෙනත් යෙදුමකට පැවරීමට හැකිය."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ස්ථාන යාවත්කාලීන දැනුම්දීම් පාලනය කරන්න"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ස්ථානීය යාවත්කාලින දැනුම්දීම් රේඩියෝවෙන් සබල/අබල කිරීමට යෙදුමට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වල භාවිතය සඳහා නොවේ."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"පිරික්සුම් ගුණාංග වෙත ප්‍රවේශය"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"යෙදුමකට DRM  සහතික ඉවත් කිරීමට ඉඩ දේ. සාමාන්‍ය යෙදුම් වලට කිසිදා අවශ්‍ය නොවේ."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"වාහක පණිවිඩ යැවීමේ සේවාවට බදින්න"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"වාහක සේවාව ඉහල මට්ටමේ අතුරු මුහුණතක් වෙත සම්බන්ධ කිරීමට ධාරකයාට අවසර දෙන්න. සාමාන්‍ය යෙදුම්වලට කිසි විටෙක අවශ්‍ය නොවෙයි."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"හඬ අන්තර්ක්‍රියා සේවාව සමග අන්තර්ක්‍රියා කරන්න"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"දැනට සක්‍රිය හඬ අන්තර්ක්‍රියා සේවාව සමග අන්තර්ක්‍රියා කිරීමට හිමිකරුට ඉඩ දෙයි. සාමාන්‍ය යෙදුම් සඳහා කිසිදා අවශ්‍ය නොවිය යුතුය."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"මුරපද නීති සකස් කිරීම"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"තිර අගුලු මුරපද සහ PIN තුළ ඉඩ දෙන දිග සහ අනුලකුණු පාලනය කිරීම."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"තිරය අගුළු ඇරීමේ උත්සාහයන් නිරීක්ෂණය කරන්න"</string>
@@ -1138,6 +1149,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ස්ථාපිත කොට ඇති පැකේජයක් සත්‍යාපනයට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"පැකේජ සත්‍යාපකයක් වෙත බඳින්න"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"පැකේජ සත්‍යාපක ඉල්ලීම් වලට දරන්නාට ඉඩ ලබා දේ. සාමාන්‍ය යෙදුම් සඳහා කිසිසේත් අවශ්‍ය නොවේ."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"චේතනාන්විත පෙරහන සත්‍යාපනය කරන්න"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"චේතනාන්විත පෙරහනක් සත්‍යාපනය කර තිබේද නැද්ද යන්න පරීක්ෂා කිරීමට යෙදුමට ඉඩ දෙයි."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"චේතනාන්විත පෙරහන් සත්‍යාපනකාරකයක් වෙත බඳින්න"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"චේතනාන්විත පෙරහන් සත්‍යාපනකාරකවල ඉල්ලීම් සිදු කිරීමට දරන්නාට ඉඩ දෙයි. සාමාන්‍ය යෙදුම් සඳහා කිසිදා අවශ්‍ය නොවිය යුතුය."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"ශ්‍රේණිගත පොට ප්‍රවේශ කිරීම"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API භාවිතයෙන් අනුක්‍රම තොට වෙත ප්‍රවේශ වීමට රඳවනයට අවසර දෙන්න."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"බාහිර අන්තර්ගත සැපයුම්කරුවන් වෙත ප්‍රවේශය"</string>
@@ -1563,6 +1578,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"දවස අඩු කරන්න"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"වසර වැඩි කරන්න"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"වසර අඩු කරන්න"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"පෙර මාසය"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"ඊළඟ මාසය"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"අවලංගු කරන්න"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"මකන්න"</string>
@@ -1815,7 +1832,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"මිනිත්තු තෝරන්න"</string>
     <string name="select_day" msgid="7774759604701773332">"මාසය සහ දිනය තෝරන්න"</string>
     <string name="select_year" msgid="7952052866994196170">"වසර තෝරන්න"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> තෝරාගෙන ඇත"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> මකා දමන ලදි"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"වැඩ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"මෙම තීරයේ ඇමුණුම ඉවත් කිරීමට, ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවේ ස්පර්ශ කර අල්ලා සිටින්න."</string>
@@ -1826,6 +1842,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ගැලවීමට පෙර PIN විමසන්න"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ගැලවීමට පෙර අගුළු අරින රටාව සඳහා අසන්න"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ගැලවීමට පෙර මුරපදය විමසන්න"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"බැටරි ආයු කාලය වැඩිදියුණු කිරීමට උදවු කිරීමට, බැටරි සුරැකුම ඔබේ උපාංගයේ ක්‍රියාකාරීත්වය අඩුකරන අතර කම්පනය, පිහිටීම් සේවා, සහ බොහෝමයක් පසුබිම් දත්ත සීමා කරයි. ඔබ ඒවා විවෘත නොකරන්නේ නම් මිස ඊමේල්, පණිවිඩකරණය, සහ සමමුහුර්ත කිරීම මත රඳා පවතින වෙනත් යෙදුම් යාවත්කාලීන නොවිය හැකිය.\n\nඔබේ උපාංගය ආරෝපණය වන විට බැටරි සුරැකුම ස්වයංක්‍රියව අක්‍රිය වේ."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"ඔබගේ බිඳවැටුම් වේලාව <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> දී අවසන්වන තුරු"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"ඔබගේ බිදවැටුම් කාලය අවසන් වන තෙක්"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 9059038..d068ebc 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -126,9 +126,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Banner roamingu je vypnutý"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Vyhľadávanie služby"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Volanie cez Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Vypnuté"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Uprednostniť Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Uprednostniť mobilné pripojenie"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Len Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Nepresmerované"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po <xliff:g id="TIME_DELAY">{2}</xliff:g> s"</string>
@@ -587,6 +593,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Zakázať indikátor LED prenosu pri používaní fotoaparátu"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Umožňuje v predinštalovanej systémovej aplikácii zakázať indikátor LED používania fotoaparátu."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Umožňuje predinštalovanej systémovej aplikácii odosielať systémové udalosti služby fotoaparátu."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trvalé zakázanie tabletu"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"trvalé zakázanie televízora"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"trvalé vypnutie telefónu"</string>
@@ -635,6 +642,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"priame zapnutie nastavenia štandardu CDMA v televízore"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"priamo spustiť nastavenie telefónu CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Umožňuje aplikácii spustiť poskytovanie CDMA. Škodlivé aplikácie môžu spustiť poskytovanie CDMA samovoľne."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"spustiť nastavenie SIM karty"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Povolí aplikácii spracovávať žiadosti o aktiváciu SIM karty. Aplikácia môže aktiváciu vykonať priamo alebo na to môže delegovať na inú aplikáciu."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ovládanie upozornení na aktualizáciu polohy"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Umožňuje aplikácii povoliť alebo zakázať upozornenia s aktualizáciami polohy z rádia. Bežné aplikácie toto nastavenie nepoužívajú."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"prístup k vlastnostiam nahlásenia"</string>
@@ -841,6 +850,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Umožňuje aplikácii odstraňovať certifikáty DRM. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"viazať sa na službu na odosielanie správ SMS a MMS operátora"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Umožňuje držiteľovi viazať sa na najvyššiu úroveň rozhrania služby na odosielanie správ SMS a MMS operátora. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interagovať so službou hlasovej interakcie"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Umožňuje držiteľovi interagovať s momentálne aktívnymi službami hlasovej interakcie. Bežné aplikácie by toto povolenie nemali nikdy potrebovať."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastaviť pravidlá pre heslo"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Nastavte dĺžku hesiel na odomknutie obrazovky aj kódov PIN a v nich používané znaky."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Sledovať pokusy o odomknutie obrazovky"</string>
@@ -1138,6 +1149,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikácii overiť, či je možné balík nainštalovať."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"naviazať na overovateľa balíka"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"overiť filter intencií"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Umožňuje aplikácii overiť, či bol filter intencií overený."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"viazať na overenie filtra intencií"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Umožňuje držiteľovi podávať žiadosti o overenie filtra intencií. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externý prístup k poskytovateľom obsahu"</string>
@@ -1577,6 +1592,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Ubrať deň"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Pridať rok"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Ubrať rok"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Predchádzajúci mesiac"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nasledujúci mesiac"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Zrušiť"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Odstrániť"</string>
@@ -1823,7 +1840,7 @@
     <string name="restr_pin_try_later" msgid="973144472490532377">"Skúste to znova neskôr"</string>
     <string name="immersive_cling_title" msgid="8394201622932303336">"Zobrazenie na celú obrazovku"</string>
     <string name="immersive_cling_description" msgid="3482371193207536040">"Ukončite prejdením prstom z hornej časti nadol."</string>
-    <string name="immersive_cling_positive" msgid="5016839404568297683">"Rozumiem"</string>
+    <string name="immersive_cling_positive" msgid="5016839404568297683">"Dobre"</string>
     <string name="done_label" msgid="2093726099505892398">"Hotovo"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Kruhový posúvač hodín"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"Kruhový posúvač minút"</string>
@@ -1831,7 +1848,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Vyberte minúty"</string>
     <string name="select_day" msgid="7774759604701773332">"Vyberte mesiac a deň"</string>
     <string name="select_year" msgid="7952052866994196170">"Vyberte rok"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Bola vybratá položka <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Číslo <xliff:g id="KEY">%1$s</xliff:g> bolo odstránené"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Práca – <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ak chcete uvoľniť túto obrazovku, súčasne klepnite na tlačidlá Späť a Prehľad a podržte ich."</string>
@@ -1842,6 +1858,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred uvoľnením požiadať o číslo PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pred uvoľnením požiadať o bezpečnostný vzor"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pred uvoľnením požiadať o heslo"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Šetrič batérie znižuje výkonnosť vášho zariadenia a obmedzuje vibrovanie, služby určovania polohy a väčšinu údajov na pozadí, aby tak pomohol predĺžiť výdrž batérie. E-mailová aplikácia, aplikácia na odosielanie správ SMS a MMS a ďalšie aplikácie, ktoré sú založené na synchronizácii, sa pravdepodobne aktualizujú až po ich otvorení.\n\nŠetrič batérie sa automaticky vypne, keď zariadenie začnete nabíjať."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Dokým o <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> neskončí výpadok"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kým skončí vaša odstávka"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c5f78b1..249dafc4 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -126,9 +126,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Pasica za gostovanje je izklopljena"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Iskanje storitve"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Klicanje prek Wi-Fi-ja"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ni posredovano"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> po toliko sekundah: <xliff:g id="TIME_DELAY">{2}</xliff:g>"</string>
@@ -587,6 +597,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"onemogoči LED-indikator prenašanja, ko je fotoaparat v uporabi"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Dovoli že nameščeni sistemski aplikaciji, da onemogoči LED-indikator uporabe fotoaparata."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Dovoli vnaprej nameščeni sistemski aplikaciji pošiljanje obvestil sistema storitve fotoaparata."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"trajno onemogočenje tabličnega računalnika"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"trajno onemogočanje televizorja"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"trajno onemogočenje telefona"</string>
@@ -635,6 +646,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"neposreden zagon nastavitve CDMA-ja za televizor"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"neposredni zagon nastavitve telefona CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Aplikaciji omogoča zagon omogočanja uporabe CDMA. Zlonamerne aplikacije lahko po nepotrebnem zaženejo omogočanje uporabe CDMA."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"nadzor obvestil o posodobitvi lokacije"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Aplikaciji dovoljuje omogočanje ali onemogočanje obvestil o posodobitvi lokacije radia. Ni za uporabo z navadnimi aplikacijami."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"dostop do lastnosti sprostitve"</string>
@@ -841,6 +856,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Aplikaciji omogoča odstranjevanje potrdil za upravljanje digitalnih pravic. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"povezovanje z operaterjevo sporočilno storitvijo"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Imetniku omogoča povezovanje z vmesnikom operaterjeve sporočilne storitve najvišje ravni. To naj ne bi bilo nikoli potrebno za navadne aplikacije."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"uporaba storitve glasovne interakcije"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Imetniku omogoča uporabo trenutno aktivne storitve glasovne interakcije. Tega ni treba nikoli uporabiti za navadne aplikacije."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Nastavitev pravil za geslo"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Nadzor nad dolžino in znaki, ki so dovoljeni v geslih in kodah PIN za odklepanje zaslona."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"nadzor nad poskusi odklepanja zaslona"</string>
@@ -1138,6 +1155,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogoča, da preveri, ali je paket mogoče namestiti."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"poveži s preverjanjem paketov"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne aplikacije."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"preverjanje filtra namena"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Aplikaciji omogoča, da preveri, ali je filter namena preverjen ali ne."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"povez. s preverjevalnikom filtra namena"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Imetniku omogoča zahtevanje preverjevalnikov filtra namena. Tega se ne sme nikoli uporabiti za navadne aplikacije."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"zunanji dostop do ponudnikov vsebine"</string>
@@ -1577,6 +1598,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Zmanjšanje vrednosti za dan"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Povečanje vrednosti za leto"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Zmanjšanje vrednosti za leto"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prejšnji mesec"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Naslednji mesec"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Tipka Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Prekliči"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tipka Delete"</string>
@@ -1831,7 +1854,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Izberite minute"</string>
     <string name="select_day" msgid="7774759604701773332">"Izberite mesec in dan"</string>
     <string name="select_year" msgid="7952052866994196170">"Izberite leto"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Izbrano: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Številka <xliff:g id="KEY">%1$s</xliff:g> je izbrisana"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> za delo"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Če želite odpeti ta zaslon, se hkrati dotaknite tipk Nazaj in Pregled ter ju pridržite."</string>
@@ -1842,6 +1864,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Pred odpenjanjem vprašaj za PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Pred odpenjanjem vprašaj za geslo"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Varčevanje z energijo akumulatorja podaljša čas njegovega delovanja tako, da zmanjša zmogljivost delovanja naprave in omeji vibriranje, lokacijske storitve ter prenos večine podatkov v ozadju. Aplikacije za e-pošto, sporočanje in drugo, ki uporabljajo sinhroniziranje, se morda ne posodabljajo, razen če jih odprete.\n\nVarčevanje z energijo akumulatorja se samodejno izklopi med polnjenjem akumulatorja naprave."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Do konca prekinitve delovanja ob <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Do konca časa nedelovanja"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 189113a..f70b5e4 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -125,9 +125,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Банер роминга је искључен"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Претраживање услуге"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Позивање преко Wi-Fi-ја"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Није прослеђено"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> након <xliff:g id="TIME_DELAY">{2}</xliff:g> секунде(и)"</string>
@@ -586,6 +596,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"онемогући пренос LED осветљења индикатора док се камера користи"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Дозвољава унапред инсталираној системској апликацији да онемогући LED осветљење индикатора за коришћење камере."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Дозвољава унапред инсталираној системској апликацији да шаље догађаје система за услугу камере."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"трајно онемогућавање таблета"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"трајно онемогућавање ТВ-а"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"трајно онемогућавање телефона"</string>
@@ -634,6 +645,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"директно покретање CDMA подешавања ТВ-а"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"директно покретање подешавања CDMA телефона"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дозвољава апликацији да покрене доделу кодираног вишеструког приступа (CDMA). Злонамерне апликације могу да покрећу CDMA без потребе."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"контрола обавештења о ажурирању локације"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дозвољава апликацији да омогући/онемогући обавештења о ажурирању локација са радија. Не користе је уобичајене апликације."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"приступ својствима провере"</string>
@@ -840,6 +855,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Дозвољава апликацији да уклања DRM сертификате. Никада не би требало да се користи за обичне апликације."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"повезивање са услугом за размену порука мобилног оператера"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Дозвољава власнику да се повеже са интерфејсом највишег нивоа за услугу за размену порука мобилног оператера. Никада не би требало да буде потребно за стандардне апликације."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"комуницирај са услугом гласовне интеракције"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Дозвољава власнику да комуницира са тренутно активном услугом гласовне интеракције. Никада не би требало да буде потребна за уобичајене апликације."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Подешавање правила за лозинку"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Контролише дужину и знакове дозвољене у лозинкама и PIN-овима за закључавање екрана."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Надгледање покушаја откључавања екрана"</string>
@@ -1137,6 +1154,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозвољава апликацији да верификује да ли је пакет могуће инсталирати."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обавезивање на верификатор пакета"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"верификација intent филтера"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Дозвољава апликацији са провери да ли је intent филтер верификован."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"повезив. са верификатором intent филтера"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Дозвољава власнику да упућује захтеве верификаторима intent филтера. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"приступ добављачима садржаја споља"</string>
@@ -1569,6 +1590,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Смањивање дана"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Повећавање године"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Смањивање године"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Претходни месец"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Следећи месец"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Откажи"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Избриши"</string>
@@ -1822,7 +1845,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Изаберите минуте"</string>
     <string name="select_day" msgid="7774759604701773332">"Изаберите месец и дан"</string>
     <string name="select_year" msgid="7952052866994196170">"Изаберите годину"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Изабрали сте <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Избрисали сте <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> на послу"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Да бисте откачили овај екран, истовремено додирните и задржите Назад и Преглед."</string>
@@ -1833,6 +1855,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Тражи PIN пре откачињања"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Тражи лозинку пре откачињања"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Да би продужила време трајања батерије, уштеда батерије смањује перформансе уређаја и ограничава вибрацију, услуге локације и већину позадинских података. Имејл, размена порука и друге апликације које се ослањају на синхронизацију можда неће да се ажурирају ако их не отворите.\n\nУштеда батерије се аутоматски искључује када се уређај пуни."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Док се одмор не заврши у <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Док се одмор не заврши"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 3973636..bf763e5 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Roamingbanner av"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Söker efter tjänst"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-samtal"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Vidarebefordras inte"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g><xliff:g id="DIALING_NUMBER">{1}</xliff:g> efter <xliff:g id="TIME_DELAY">{2}</xliff:g> sekunder"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"inaktivera LED-sändningsindikator när kameran används"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Tillåter att en förinstallerad systemapp inaktiverar LED-indikatorn för kameranvändning."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Tillåter att en förinstallerad systemapp skickar systemmeddelanden till kameratjänsten."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"inaktivera surfplattan permanent"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"inaktivera tv:n permanent"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"inaktivera telefonen permanent"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"starta konfiguration av CDMA-tv direkt"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"starta CDMA-telefoninställningar direkt"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Tillåter att appen startar CDMA-anslutning. Skadliga appar kan starta CDMA-anslutningar i onödan."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"styra meddelanden för platsuppdatering"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Tillåter att appen aktiverar/inaktiverar meddelanden om platsuppdateringar från radion. Används inte av vanliga appar."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"få åtkomst till incheckningsegenskaper"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Tillåter ett program att ta bort DRM-certifikat. Behövs inte för vanliga appar."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"binda till en operatörs meddelandetjänst"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en operatörs meddelandetjänst. Ska inte behövas för vanliga appar."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"interagera med rösttjänsten"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Innehavaren får interagera med den för tillfället aktiva rösttjänsten. Detta ska inte behövas för vanliga appar."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Ange lösenordsregler"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Styr tillåten längd och tillåtna tecken i lösenord och pinkoder för skärmlåset."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Övervaka försök att låsa upp skärmen"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillåter att appen kontrollerar om ett paket går att installera."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"binda till en paketverifierare"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"verifiera intent-filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Tillåter att appen kontrollerar om ett intent-filter har verifierats eller inte."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"binda till en intent-filterverifierare"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Tillåter att innehavaren skickar begäranden till intent-filterverifierare. Behövs inte för vanliga appar."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"komma åt innehållsleverantörer externt"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Minska dagar"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Öka år"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Minska år"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Föregående månad"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Nästa månad"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Avbryt"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Välj minuter"</string>
     <string name="select_day" msgid="7774759604701773332">"Välj månad och dag"</string>
     <string name="select_year" msgid="7952052866994196170">"Välj år"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> har markerats"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> har tagits bort"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> för arbetet"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Om du vill lossa skärmen trycker du länge på Tillbaka och Översikt samtidigt."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Be om pinkod innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Be om upplåsningsmönster innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Be om lösenord innan skärmen slutar fästas"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"I batterisparläget reduceras enhetens prestanda så att batteriet ska räcka längre och vibration, platstjänster samt den mesta användningen av bakgrundsdata begränsas. Det kan hända att appar för e-post, sms och annat som kräver synkronisering inte uppdateras förrän du öppnar dem.\n\nBatterisparläget inaktiveras automatiskt när enheten laddas."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Tills avbrottstiden är slut <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Tills avbrottstiden är slut"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 0f1d7ae..c799a72 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Zima Bango la Uzururaji"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Inatafuta Huduma"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Upigaji Simu kwa Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Imezimwa"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Inayopendelea Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Inayopendelea mitandao ya simu za mkononi"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi pekee"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Haijatumiwa mwingine"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> baada ya sekunde <xliff:g id="TIME_DELAY">{2}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"zima LED ya kisambaza kiashirio wakati kamera inatumika"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Huruhusu mfumo wa programu iliyosakinishwa awali kuzima kamera isitumie kiashirio cha LED."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Huruhusu mfumo wa programu iliyosakinishwa awali kutuma kwenye kamera matukio ya mfumo wa huduma."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"zima kompyuta ndogo kabisa"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"zima runinga kabisa"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"simu iliyolemazwa kabisa"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"anzisha usanidi wa runinga ya CDMA moja kwa moja"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"anzisha moja kwa moja usanidi wa simu ya CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Inaruhusu programu kuanza ugawaji wa CDMA. Programu hasidi zinaweza anza ugawaji wa CDMA usio wa lazima."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"anzisha usanidi wa SIM kadi"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Inaruhusu programu kushughulikia maombi ya kuanza kutumia SIM kadi. Programu inaweza kuanzisha SIM kadi moja kwa moja au inaweza kutoa mamlaka ya kuanzisha kwa programu nyingine."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"dhibiti arifa za usasishaji mahali"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Huruhusu kuwasha au kuzima arifa za masasisho ya mahali kutoka kwa redio. Sio ya kutumiwa kwenye programu za kawaida."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"fikia mipangilio ya ukaguzi"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Huruhusu programu kuondoa vyeti vya DRM. Haipaswi kuhitajika kwa programu za kawaida kamwe."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"Shurutisha kwa huduma ya ujumbe ya mtoa huduma"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Huruhusu kishikiliaji kushurutisha kwa kiolesura cha hali ya juu cha huduma ya ujumbe ya mtoa huduma. Haipaswi kuhitajika kwa programu za kawaida."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"tumia huduma ya muingiliano wa sauti"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Humruhusu mmiliki kutumia huduma ya muingiliano wa sauti inayotumika kwa sasa. Isihitajike kamwe kwa programu za kawaida."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Kuweka kanuni za nenosiri"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Dhibiti urefu na maandishi yanayokubalika katika nenosiri la kufunga skrini na PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Kuhesabu mara ambazo skrini inajaribu kufunguliwa"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Inaruhusu programu kuthibitisha kuwa furushi linaweza kusakinishwa."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Funga kwa kithibitishaji cha furushi"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"thibitisha kichujio cha kutoa maagizo"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Inaruhusu programu kukagua ikiwa kuchujio cha kutoa maagizo kimethibitishwa au bado."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"funga kwenye kithibitishaji cha kichujio cha kutoa maagizo."</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Inaruhusu mmiliki kutuma maombi ya vithibitishaji vya kichujio cha kutoa maagizo. Haviwezi kuhitajika katika programu za kawaida."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"fikia watoa huduma nje"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Punguza siku"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Ongeza mwaka"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Punguza mwaka"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Mwezi uliopita"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Mwezi ujao"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Ghairi"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Futa"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Chagua dakika"</string>
     <string name="select_day" msgid="7774759604701773332">"Chagua mwezi na siku"</string>
     <string name="select_year" msgid="7952052866994196170">"Chagua mwaka"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> kimechaguliwa"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> kimefutwa"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ya kazini <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ili ubanue skrini hii, gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Omba PIN kabla hujabandua"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Omba mchoro wa kufungua kabla hujabandua"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Omba nenosiri kabla hujabandua"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Kusaidia kuboresha muda wa matumizi ya betri, inayookoa betri hupunguza utendaji wa kifaa chako na kupunguza mtetemo, huduma za utambuzi wa mahali, na data nyingi ya chini chini. Barua pepe, ujumbe na programu nyingine zinazotege,ea usawazishaji huenda zisisasishwe usipozifungua.\n\nInayookoa betri hujizima kiotomatiki kifaa chako kinapokuwa kinachaji."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hadi <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> wakati wa kutotenda kazi kwa kifaa chako unapoisha"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hadi muda wako wa hali tuli utakapoisha"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index c473bc1..e491ed0 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"ரோமிங் பேனர் முடக்கப்பட்டது"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"சேவையைத் தேடுகிறது"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"வைஃபை அழைப்பு"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"முடக்கப்பட்டுள்ளது"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"வைஃபைக்கு முன்னுரிமை"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"செல்லுலாருக்கு முன்னுரிமை"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"வைஃபை மட்டும்"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: பகிரப்படவில்லை"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> வினாடிகளுக்குப் பிறகு <xliff:g id="DIALING_NUMBER">{1}</xliff:g> ஐப் பகிர்"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"கேமரா பயன்பாட்டில் இருக்கும்போது டிரான்ஸ்மிட் இன்டிகேட்டர் LED ஐ முடக்குதல்"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"இன்டிகேட்டர் LED ஐ கேமரா பயன்படுத்துவதை முடக்க, முன்நிறுவப்பட்ட அமைப்பு பயன்பாட்டை அனுமதிக்கிறது."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"முறைமை நிகழ்வுகள் பற்றிய கேமரா சேவை அறிவிப்புகளை அனுப்ப, முன்நிறுவப்பட்ட முறைமை பயன்பாட்டை அனுமதிக்கும்."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"டேப்லெட்டை நிரந்தரமாக முடக்குதல்"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"டிவியை நிரந்தரமாக முடக்குதல்"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"தொலைபேசியை நிரந்தரமாக முடக்குதல்"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA TV அமைவிலிருந்து நேரடியாக தொடங்குதல்"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA தொலைபேசி அமைவை நேரடியாகத் தொடங்குதல்"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMA வழங்கலைத் தொடங்க, பயன்பாட்டை அனுமதிக்கிறது. தீங்குவிளைவிக்கும் பயன்பாடுகள் தேவையில்லாமல் CDMA வழங்கலைத் தொடங்கலாம்."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM கார்டு அமைவைத் துவங்கவும்"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"பயன்பாட்டை SIMஐச் செயல்படுத்துவதற்கான கோரிக்கைகளைக் கையாள அனுமதிக்கும். இந்தப் பயன்பாடு நேரடியாகச் செயல்படுத்தலை நடத்தலாம் அல்லது மற்றொரு பயன்பாட்டிடம் பொறுப்பை ஒப்படைக்கலாம்."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"இட புதுப்பிப்பு அறிவிப்புகளைக் கட்டுப்படுத்துதல்"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ரேடியோவிலிருந்து இருப்பிட புதுப்பிப்பு அறிவிப்புகளை இயக்க/முடக்க பயன்பாட்டை அனுமதிக்கிறது. சாதாரண பயன்பாடுகள் பயன்படுத்தாது."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"செக்இன் பண்புகளின் அணுகல்"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM சான்றிதழ்களை அகற்ற, பயன்பாட்டை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"மொபைல் நிறுவனச் செய்தியிடல் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"மொபைல் நிறுவனச் செய்தியிடல் சேவையின் உயர்-நிலை இடைமுகத்துடன் ஹோல்டரை இணைக்க அனுமதிக்கும். இயல்பான பயன்பாடுகளுக்குத் தேவைப்படாது."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"குரல் மூலம் தொடர்புகொள்வதற்கான சேவையுடன் ஊடாடுதல்"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"தற்போது செயலில் உள்ள குரல் மூலம் தொடர்புகொள்வதற்கான சேவையுடன் ஊடாட ஹோல்டரை அனுமதிக்கும். இயல்பு பயன்பாடுகளுக்கு எப்போதும் தேவைப்படாது."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"கடவுச்சொல் விதிகளை அமைக்கவும்"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"திரைப் பூட்டின் கடவுச்சொற்கள் மற்றும் பின்களில் அனுமதிக்கப்படும் நீளத்தையும் எழுத்துக்குறிகளையும் கட்டுப்படுத்தும்."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"திரைத் திறக்க முயற்சிகளைக் கண்காணித்தல்"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"பேக்கேஜ் நிறுவுவதற்கு ஏற்றதா என்பதைச் சரிபார்க்க, பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"தொகுப்பு சரிபார்ப்பானுடன் இணைத்தல்"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"தொகுப்பைச் சரிபார்ப்பிற்கான கோரிக்கைகளை உருவாக்க, ஹோல்டரை அனுமதிக்கிறது. சாதாரண பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"இன்டென்ட் வடிப்பானைச் சரிபார்த்தல்"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"இன்டென்ட் வடிப்பான் சரிபார்க்கப்பட்டதா அல்லது இல்லையா என்பதைச் சோதிக்க, பயன்பாட்டை அனுமதிக்கும்."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"இன்டென்ட் வடிப்பான் சரிபார்ப்பியுடன் இணைத்தல்"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"இன்டென்ட் வடிப்பான் சரிபார்ப்பிகளின் கோரிக்கைகளை உருவாக்க ஹோல்டரை அனுமதிக்கும். சாதாரணப் பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"தொடர் போர்ட்களின் அணுகல்"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API ஐப் பயன்படுத்தி தொடர் போர்ட்களை அணுக ஹோல்டரை அனுமதிக்கிறது."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"வெளிப்புறமாக வழங்கப்படும் உள்ளடக்கத்திற்கான அணுகல்"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"நாளினைக் குறை"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"வருடத்தை அதிகரி"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"வருடத்தைக் குறை"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"முந்தைய மாதம்"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"அடுத்த மாதம்"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ரத்துசெய்"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"நீக்கு"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"நிமிடத்தைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="select_day" msgid="7774759604701773332">"மாதம் மற்றும் தேதியைத் தேர்ந்தெடுக்கவும்"</string>
     <string name="select_year" msgid="7952052866994196170">"ஆண்டைத் தேர்ந்தெடுக்கவும்"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> தேர்ந்தெடுக்கப்பட்டது"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> நீக்கப்பட்டது"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"பணியிடம் <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"இந்தத் திரையை விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடித்திருக்கவும்."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"அகற்றும் முன் PINஐக் கேள்"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"அகற்றும் முன் திறத்தல் வடிவத்தைக் கேள்"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"அகற்றும் முன் கடவுச்சொல்லைக் கேள்"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"பேட்டரி ஆயுளை மேம்படுத்த, பேட்டரி சேமிப்பான் உங்கள் சாதனத்தின் செயல்திறனைக் குறைத்து, அதிர்வு, இடச் சேவைகள் மற்றும் பெரும்பாலான பின்புலத் தரவு போன்றவற்றைக் கட்டுப்படுத்துகிறது. ஒத்திசைவைச் சார்ந்துள்ள மின்னஞ்சல், செய்தியிடல் மற்றும் பிற பயன்பாடுகளானது அவற்றைத் திறக்கும்வரையில் புதுப்பிக்கப்படாமல் போகக்கூடும்.\n\nஉங்கள் ஃபோன் சார்ஜ் செய்யப்படும்போது, பேட்டரி சேமிப்பான் தானாகவே முடங்கும்."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> முடியும் வரை"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"செயலற்ற நேரம் முடியும் வரை"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 5bc59c3..3b5c56f 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"రోమింగ్ బ్యానర్ ఆఫ్‌లో ఉంది"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"సేవ కోసం శోధిస్తోంది"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi కాలింగ్"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"ఆఫ్‌లో ఉంది"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fiకి ప్రాధాన్యత"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"సెల్యులార్‌కి ప్రాధాన్యత"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi మాత్రమే"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ఫార్వార్డ్ చేయబడలేదు"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> సెకన్ల తర్వాత <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"కెమెరా ఉపయోగంలో ఉన్నప్పుడు ప్రసరణ సూచీ LEDని నిలిపివేయడం"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"కెమెరా వినియోగ సూచీ LEDని నిలిపివేయడానికి ముందే ఇన్‌స్టాల్ చేయబడిన సిస్టమ్ అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"కెమెరా సేవకి సిస్టమ్ ఈవెంట్‌లను పంపడానికి ముందే ఇన్‌స్టాల్ చేసిన సిస్టమ్ అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"టాబ్లెట్‌ను శాశ్వతంగా నిలిపివేయడం"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"టీవీని శాశ్వతంగా నిలిపివేయడం"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ఫోన్‌ను శాశ్వతంగా నిలిపివేయడం"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA టీవీ సెటప్‌ను నేరుగా ప్రారంభించడం"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA ఫోన్ సెటప్‌ను నేరుగా ప్రారంభించడం"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"CDMA కేటాయింపును ప్రారంభించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. హానికరమైన అనువర్తనాలు CDMA కేటాయింపును అనవసరంగా ప్రారంభించవచ్చు."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM కార్డ్ సెటప్‌ను ప్రారంభించండి"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"SIM సక్రియ అభ్యర్థనలను నిర్వహించడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సక్రియ చర్యను అనువర్తనం నేరుగా నిర్వహించవచ్చు లేదా మరొక అనువర్తనానికి అప్పగించవచ్చు."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"స్థాన నవీకరణ నోటిఫికేషన్‌లను నియంత్రించడం"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"రేడియో నుండి స్థానం నవీకరణ నోటిఫికేషన్‌లను ప్రారంభించడానికి/నిలిపివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాల ద్వారా ఉపయోగించడానికి ఉద్దేశించినది కాదు."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"ప్రవేశ లక్షణాలను ప్రాప్యత చేయడం"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"DRM ప్రమాణపత్రాలను తీసివేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"క్యారియర్ సందేశ సేవకు అనుబంధించడం"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"క్యారియర్ సందేశ సేవ యొక్క అగ్ర-స్థాయి ఇంటర్‌ఫేస్‌కు అనుబంధించడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"వాయిస్ ప్రతిస్పందక సేవతో పరస్పర చర్య చేయడం"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"ప్రస్తుతం సక్రియంగా ఉన్న వాయిస్ ప్రతిస్పందక సేవతో పరస్పర చర్య చేయడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"పాస్‌వర్డ్ నియమాలను సెట్ చేయండి"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"స్క్రీన్ లాక్ పాస్‌వర్డ్‌లు మరియు PINల్లో అనుమతించబడిన పొడవు మరియు అక్షరాలను నియంత్రిస్తుంది."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"స్క్రీన్-అన్‌లాక్ ప్రయత్నాలను పర్యవేక్షించండి"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ప్యాకేజీ ఇన్‌స్టాల్ చేయవచ్చని ధృవీకరించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ప్యాకేజీ తనిఖీదారుకు అనుబంధించడం"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"ప్యాకేజీ తనిఖీదారుల యొక్క అభ్యర్థనలు చేయడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ఉద్దేశిత ఫిల్టర్‌ను ధృవీకరించడం"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ఉద్దేశిత ఫిల్టర్ ధృవీకరించబడిందో లేదో తనిఖీ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"ఉద్దేశిత ఫిల్టర్ వెరిఫైయర్‌కి నిర్బంధించడం"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"ఉద్దేశిత ఫిల్టర్ వెరిఫైయర్‌ల అభ్యర్థనలు చేయడానికి హోల్డర్‌ను అనుమతిస్తుంది. సాధారణ అనువర్తనాలకు ఎప్పటికీ అవసరం ఉండదు."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"శ్రేణి పోర్ట్‌లను ప్రాప్యత చేయడం"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"శ్రేణి నిర్వాహికి APIని ఉపయోగించి శ్రేణి పోర్ట్‌లను ప్రాప్యత చేయడానికి హోల్డర్‌ను అనుమతిస్తుంది."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"కంటెంట్ ప్రదాతలను బాహ్యంగా ప్రాప్యత చేయడం"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"రోజును తగ్గించండి"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"సంవత్సరాన్ని పెంచండి"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"సంవత్సరాన్ని తగ్గించండి"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"మునుపటి నెల"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"తదుపరి నెల"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"రద్దు చేయి"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"తొలగించు"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"నిమిషాలను ఎంచుకోండి"</string>
     <string name="select_day" msgid="7774759604701773332">"నెల మరియు రోజును ఎంచుకోండి"</string>
     <string name="select_year" msgid="7952052866994196170">"సంవత్సరాన్ని ఎంచుకోండి"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> ఎంచుకోబడింది"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> తొలగించబడింది"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"కార్యాలయం <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"ఈ స్క్రీన్‌ను అన్‌పిన్ చేయడానికి, వెనుకకు మరియు అవలోకనం బటన్‌లను ఒకేసారి నొక్కి, ఉంచండి."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"అన్‌పిన్ చేయడానికి ముందు పిన్‌ కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ నమూనా కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"బ్యాటరీ జీవితకాలాన్ని మెరుగుపరచడంలో సహాయపడటానికి, బ్యాటరీ సేవర్ మీ పరికరం పనితీరును తగ్గిస్తుంది మరియు వైబ్రేషన్‌ను, స్థాన సేవలను మరియు ఎక్కువ నేపథ్య డేటాను పరిమితం చేస్తుంది. ఇమెయిల్, మెసేజింగ్ మరియు సమకాలీకరణపై ఆధారపడే ఇతర అనువర్తనాలు మీరు వాటిని తెరిస్తే మినహా నవీకరించబడవు.\n\nమీ పరికరం ఛార్జ్ అవుతున్నప్పుడు బ్యాటరీ సేవర్ స్వయంచాలకంగా ఆఫ్ అవుతుంది."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"మీ వృథా సమయం <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>కి ముగిసే వరకు"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"మీ వృథా సమయం ముగిసేవరకు"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index adbe8c9..cfe679d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"ปิดโรมมิ่งแบนเนอร์"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"กำลังค้นหาบริการ"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"การโทรผ่าน Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: ไม่ได้โอนสาย"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> หลังผ่านไป <xliff:g id="TIME_DELAY">{2}</xliff:g> วินาที"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"ปิดไฟสัญญาณ LED เมื่อใช้งานกล้อง"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"อนุญาตให้แอปพลิเคชันระบบที่ติดตั้งล่วงหน้าปิดไฟสัญญาณ LED ของกล้อง"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"อนุญาตให้แอปพลิเคชันระบบที่ติดตั้งล่วงหน้าส่งกิจกรรมระบบไปยังบริการของกล้อง"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ปิดการใช้งานแท็บเล็ตอย่างถาวร"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"ปิดใช้ทีวีถาวร"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ปิดการใช้งานโทรศัพท์ถาวร"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"เริ่มตั้งค่าทีวี CDMA โดยตรง"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"เริ่มการตั้งค่าโทรศัพท์ CDMA โดยตรง"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"อนุญาตให้แอปพลิเคชันเริ่มการให้บริการ CDMA แอปพลิเคชันที่เป็นอันตรายอาจเริ่มการให้บริการ CDMA โดยไม่จำเป็นได้"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"ควบคุมการแจ้งเตือนการอัปเดตตำแหน่ง"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"อนุญาตให้แอปพลิเคชันเปิด/ปิดใช้งานการแจ้งเตือนการอัปเดตตำแหน่งจากวิทยุ ไม่ใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"เข้าถึงคุณสมบัติการเช็คอิน"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"อนุญาตให้แอปพลิเคชันนำใบรับรอง DRM ออก แอปทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"เชื่อมโยงกับบริการรับส่งข้อความของผู้ให้บริการ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"อนุญาตให้แอปพลิเคชันเชื่อมโยงกับอินเทอร์เฟซระดับบนสุดของบริการรับส่งข้อความของผู้ให้บริการ ไม่ควรใช้สำหรับแอปธรรมดาทั่วไป"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"โต้ตอบกับบริการโต้ตอบด้วยเสียง"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"อนุญาตให้แอปโต้ตอบกับบริการโต้ตอบด้วยเสียงที่ใช้งานอยู่ในขณะนี้ แอปทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"ตั้งค่ากฎรหัสผ่าน"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"ควบคุมความยาวและอักขระที่สามารถใช้ในรหัสผ่านของการล็อกหน้าจอและ PIN"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"ตรวจสอบความพยายามในการปลดล็อกหน้าจอ"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพ็กเกจสามารถติดตั้งได้หรือไม่"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพ็กเกจ"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพ็กเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"ยืนยันตัวกรองความตั้งใจ"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"อนุญาตให้แอปตรวจสอบว่ามีการยืนยันตัวกรองความตั้งใจหรือไม่"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"เชื่อมโยงกับการยืนยันตัวกรองความตั้งใจ"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"อนุญาตให้แอปส่งคำขอการยืนยันตัวกรองความตั้งใจ แอปทั่วไปไม่จำเป็นต้องใช้"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"เข้าถึงผู้ให้บริการเนื้อหาจากภายนอก"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"ลดวัน"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"เพิ่มปี"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"ลดปี"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"เดือนที่แล้ว"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"เดือนหน้า"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"ยกเลิก"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"ลบ"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"เลือกนาที"</string>
     <string name="select_day" msgid="7774759604701773332">"เลือกเดือนและวัน"</string>
     <string name="select_year" msgid="7952052866994196170">"เลือกปี"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"เลือก <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"ลบ <xliff:g id="KEY">%1$s</xliff:g> แล้ว"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g>ที่ทำงาน"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"หากต้องการเลิกตรึงหน้าจอนี้ แตะ \"กลับ\" และ \"ภาพรวม\" ค้างไว้พร้อมกัน"</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"ขอ PIN ก่อนเลิกตรึง"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"ขอรูปแบบการปลดล็อกก่อนเลิกตรึง"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"ขอรหัสผ่านก่อนเลิกตรึง"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"เพื่อช่วยปรับปรุงอายุการใช้งานแบตเตอรี่ โหมดประหยัดแบตเตอรี่จะลดการทำงานของอุปกรณ์และจำกัดการสั่น บริการตำแหน่ง และข้อมูลแบ็กกราวด์ส่วนใหญ่ สำหรับอีเมล การรับส่งข้อความ และแอปอื่นๆ ที่ใช้การซิงค์จะไม่อัปเดตหากคุณไม่เปิดขึ้นมา\n\nโหมดประหยัดแบตเตอรี่จะปิดโดยอัตโนมัติขณะชาร์จอุปกรณ์"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"จนกว่าจะสิ้นสุดช่วงเวลาที่เครื่องไม่ทำงานในเวลา <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"จนกว่าจะสิ้นสุดช่วงเวลาเครื่องไม่ทำงาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 978939b..fc06174 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Naka-off ang Banner ng Roaming"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Naghahanap ng Serbisyo"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Pagtawag sa pamamagitan ng Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Naka-off"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Mas gusto ang Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Mas gusto ang cellular"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Wi-Fi lang"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Hindi naipasa"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> pagkatapos ng <xliff:g id="TIME_DELAY">{2}</xliff:g> (na) segundo"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"i-disable ang LED na tagapagpahiwatig kapag ginagamit ang camera"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Pinapayagan ang isang paunang na-install na application ng system na i-disable ang LED na tagapagpahiwatig ng paggamit sa camera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Pinapayagan ang isang pre-installed na system application na ipadala ang mga kaganapan ng system sa serbisyo ng camera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"permanenteng huwag paganahin ang tablet"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"permanenteng i-disable ang TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"permanenteng huwag paganahin ang telepono"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"direktang simulan ang pag-setup ng CDMA TV"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"direktang simulan ang pag-set up ng CDMA na telepono"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Pinapayagan ang app na simulan ang paglalaan ng CDMA. Maaaring simulan nang hindi kinakailangan ng nakakahamak na apps ang paglalaan ng CDMA."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"simulan ang pag-set up ng SIM card"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Nagbibigay-daan sa app na mangasiwa ng mga kahilingan sa pag-activate ng SIM. Maaaring direktang magsagawa ang app ng pag-activate o maaari nitong ipasa ang tungkulin sa ibang app."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kotrolin ang mga notification ng pag-update ng lokasyon"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Pinapayagan ang app na paganahin/huwag paganahain ang mga notification ng update sa lokasyon mula sa radyo. Hindi para sa paggamit ng normal na apps."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"i-access ang mga katangian ng checkin"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Nagbibigay-daan sa isang application na alisin ang mga DRM certficate. Hindi dapat kailanman kailanganin para sa karaniwang apps."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"sumailalim sa isang serbisyo ng pagmemensahe ng carrier"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Binibigyang-daan ang may-ari na sumailalim sa interface sa nangungunang antas ng isang serbisyo ng pagmemensahe ng carrier. Hindi kailanman dapat kailanganin para sa mga normal na app."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"makipag-ugnayan sa pamamagitan ng serbisyo sa pakikipag-ugnayan gamit ang boses"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Pinapayagan ang may-ari na makipag-ugnayan sa pamamagitan ng kasalukuyang aktibong serbisyo sa pakikipag-ugnayan gamit ang boses. Hindi kailanman dapat kailanganin para sa mga normal na app."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Magtakda ng mga panuntunan sa password"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrolin ang haba at ang mga character na pinapayagan sa mga password at PIN sa lock ng screen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Subaybayan ang mga pagsubok sa pag-unlock ng screen"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pinapayagan ang app na i-verify kung ang isang package ay nai-install."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sumailalim sa taga-verify ng package"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"i-verify ang intent filter"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Nagbibigay-daan sa app na suriin kung na-verify o hindi ang isang intent filter."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"isailalim sa verifier ng intent filter"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Nagbibigay-daan sa may-ari na gumawa ng mga kahilingan ng mga verifier ng intent filter. Hindi kailanman dapat kailanganin para sa mga normal na app."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"panlabas na mag-access ng mga provider ng nilalaman"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Bawasan ang araw"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Dagdagdan ang taon"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Bawasan ang taon"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Nakaraang buwan"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Susunod na buwan"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Kanselahin"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Tanggalin"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Pumili ng mga minuto"</string>
     <string name="select_day" msgid="7774759604701773332">"Pumili ng buwan at araw"</string>
     <string name="select_year" msgid="7952052866994196170">"Pumili ng taon"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Napili ang <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Tinanggal ang <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> sa Trabaho"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Upang i-unpin ang screen na ito, pindutin nang matagal ang Bumalik at Overview nang sabay-sabay."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Humingi ng PIN bago mag-unpin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Humingi ng password bago mag-unpin"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Upang matulungang pagbutihin ang tagal ng baterya, binabawasan ng pangtipid ng baterya ang pagganap ng iyong device at nililimitahan ang pag-vibrate, mga serbisyo ng lokasyon at karamihan sa data ng background. Maaaring hindi mag-update ang email, pagmemensahe at iba pang mga app na umaasa sa pagsi-sync maliban kung buksan mo ang mga iyon.\n\nAwtomatikong nag-o-off ang pangtipid ng baterya kapag nagcha-charge ang iyong device."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Hanggang sa matapos ang iyong downtime nang <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Hanggang magtapos ang iyong downtime"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 6c80b92..398a30a 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Dolaşım Başlığı Kapalı"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Hizmet Aranıyor"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Kablosuz Çağrı"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yönlendirilmedi"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="TIME_DELAY">{2}</xliff:g> saniye sonra <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"Kamera kullanımda iken iletim göstergesi LED\'ini devre dışı bırak"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Önceden yüklenmiş bir sistem uygulamasına kamera kullanım göstergesi LED\'ini devre dışı bırakma izni verir."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Önceden yüklü sistem uygulamalarının, sistem etkinliklerini kamera hizmetine göndermesine izin verir."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"tableti kalıcı olarak devre dışı bırak"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"TV\'yi kalıcı olarak devre dışı bırakma"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"telefonu tamamen devre dışı bırak"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"CDMA TV kurulumunu doğrudan başlatma"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA telefon kurulumunu doğrudan başlat"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Uygulamaya, CDMA provizyon uygulaması başlatma izni verir. Kötü amaçlı uygulamalar gereksiz yere CDMA provizyon uygulaması başlatabilir."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"konum güncelleme bildirimlerini denetle"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Uygulamaya, radyo iletişimiyle konum güncelleme bildirimlerini etkinleştirme/devre dışı bırakma izni verir. Normal uygulamaların kullanımına yönelik değildir."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"erişim giriş özellikleri"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Uygulamaya, DRM sertifikalarını kaldırma izin verir. Normal uygulamalar için asla gerekmemelidir."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"operatör mesajlaşma hizmetine bağlan"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"İzin sahibinin, operatör mesajlaşma hizmetinin üst düzey arayüzüne bağlanmasına olanak verir. Normal uygulamalarda hiçbir zaman gerekmez."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"Sesli etkileşim hizmetiyle etkileşim kur"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"İzin sahibinin, geçerli olarak etkin durumdaki sesli etkileşim hizmetiyle etkileşim kurmasına izin verir. Normal uygulamalar için hiçbir zaman gerekli olmaz."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Şifre kuralları ayarla"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran kilidini açma şifrelerinde ve PIN\'lerde izin verilen uzunluğu ve karakterleri denetleyin."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekran kilidini açma denemelerini izle"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Uygulamaya, bir paketin yüklenebilir olduğunu doğrulama izni verir."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paket doğrulayıcıya bağlan"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"amaç filtresini doğrula"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Uygulamaya, amaç filtresinin doğrulanıp doğrulanmadığını kontrol etme izni verir."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"amaç filtresi doğrulayıcıya bağlan"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"İzin sahibine, amaç doğrulayıcılar için istekte bulunma izni verir. Normal uygulamalar için gerekli değildir."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"içerik sağlayıcılara harici olarak eriş"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Günü azalt"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Yılı artır"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yılı azalt"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Önceki ay"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Sonraki ay"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"İptal"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Sil"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Dakikayı seçin"</string>
     <string name="select_day" msgid="7774759604701773332">"Ayı ve günü seçin"</string>
     <string name="select_year" msgid="7952052866994196170">"Yılı seçin"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> seçildi"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> silindi"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (İş)"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Bu ekranın sabitlemesini kaldırmak için Geri ve Genel Bakış\'a aynı anda dokunup basılı tutun."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Sabitlemeyi kaldırmadan önce PIN\'i sor"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Pil tasarrufu özelliği, pil ömrünü iyileştirmeye yardımcı olmak için cihazın performansını düşürür, titreşimi, konum hizmetlerini ve arka plan verilerinin çoğunu sınırlar. Senkronizasyona dayalı olarak çalışan e-posta, mesajlaşma uygulamaları ve diğer uygulamalar, bunları açmadığınız sürece güncellenmeyebilir.\n\nCihazınız şarj olurken pil tasarrufu otomatik olarak kapatılır."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Bildirim istenmeyen zaman <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> saatinde sona erene kadar"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Bildirim istenmeyen zaman bitene kadar"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 07eb0e8..603f061 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -126,9 +126,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Банер роум-гу вимк."</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Пошук служби"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Дзвінок через Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Вимкнено"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi за умовчанням"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Мобільна мережа за умовчанням"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Лише Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не переслано"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> після <xliff:g id="TIME_DELAY">{2}</xliff:g> сек."</string>
@@ -587,6 +593,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"вимикати світлодіодний індикатор передавання, коли використовується камера"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Дозволяє попередньо встановленій системній програмі вимикати світлодіодний індикатор використання камери."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Попередньо встановлений системний додаток може надсилати в сервіс камери сповіщення про події системи."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"остаточно вимкнути пристрій"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"назавжди вимкнути телевізор"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"остаточно вимкнути телефон"</string>
@@ -635,6 +642,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"безпосередньо запускати налаштування телевізора CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"безпосер. поч. налашт-ня CDMA тел."</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Дозволяє програмі запускати ініціалізацію CDMA. Шкідливі програми можуть без потреби запускати ініціалізацію CDMA."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"починати налаштування SIM-карти"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Дозволяє додатку обробляти запити на активацію SIM-карти. Додаток може виконувати активацію самостійно або доручати це іншому додатку."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"контрол. сповіщ. про оновлення місцезн."</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Дозволяє програмі вмикати/вимикати сповіщення про оновлення місцезнаходження з радіо. Не для використання звичайними програмами."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"отр. дост. до власт. реєстр."</string>
@@ -841,6 +850,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Власник може видаляти сертифікати DRM. Ніколи не застосовується для звичайних додатків."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"підключатися до служби надсилання повідомлень через оператора"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Додаток зможе підключатися до інтерфейсу верхнього рівня служби надсилання повідомлень через оператора. Звичайні додатки ніколи не використовують цей дозвіл."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"взаємодіяти зі службою обміну голосовими повідомленнями"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Додаток може взаємодіяти з активною службою обміну голосовими повідомленнями. Ніколи не застосовується для звичайних додатків."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Устан. правила пароля"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Укажіть максимальну довжину та кількість символів для паролів розблокування екрана та PIN-кодів."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Відстежув. спроби розблок. екрана"</string>
@@ -1138,6 +1149,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволяє програмі перевіряти можливість встановлення пакета."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прив’язуватися до програми перевірки пакетів"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"перевірка фільтра команд"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Додаток може визначати, чи перевірено фільтр команд."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"пов’язувати з перевіркою фільтра команд"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Власник може перевірити фільтр команд. Ніколи не застосовується для звичайних додатків."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"отримув. ззовні доступ до постач. вмісту"</string>
@@ -1577,6 +1592,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"На день назад"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"На рік уперед"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"На рік назад"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Попередній місяць"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Наступний місяць"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Скасувати"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1831,7 +1848,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Виберіть хвилини"</string>
     <string name="select_day" msgid="7774759604701773332">"Виберіть місяць і день"</string>
     <string name="select_year" msgid="7952052866994196170">"Виберіть рік"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Вибрано: <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> видалено"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Робоча <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Щоб відкріпити екран, одночасно натисніть і утримуйте кнопки \"Назад\" та \"Огляд\"."</string>
@@ -1842,6 +1858,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Запитувати PIN-код перед відкріпленням"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Запитувати ключ розблокування перед відкріпленням"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Запитувати пароль перед відкріпленням"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Щоб подовжити час роботи акумулятора, функція заощадження заряду акумулятора знижує продуктивність пристрою, а також обмежує вібрацію, функції служб локації та передавання більшості фонових даних. Електронна пошта, чати й інші додатки, які синхронізуються, можуть не оновлюватися, доки ви їх не відкриєте.\n\nФункція заощадження заряду акумулятора автоматично вимикається під час заряджання пристрою."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Термін простою закінчується о <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"До завершення терміну простою"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index a5e139d..331f289 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"رومنگ بینر آف"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"سروس کی تلاش کر رہا ہے"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"‏Wi-Fi کالنگ"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"‎%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g> : فارورڈ نہیں کی گئی"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> بعد از <xliff:g id="TIME_DELAY">{2}</xliff:g> سیکنڈ"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"‏کیمرا استعمال میں ہونے پر ٹرانسمیٹ انڈیکیٹر LED کو غیر فعال کریں"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"‏پہلے سے انسٹال کردہ کسی سسٹم ایپلیکیشن کو کیمرا کے استعمال کے انڈیکیٹر LED کو غیر فعال کرنے کی اجازت دیتا ہے۔"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"پہلے سے انسٹال سسٹم ایپلیکیشن کو کیمرہ سروس سسٹم ایونٹس بھیجنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"ٹیبلیٹ کو مستقل طور پر غیر فعال کریں"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"‏مستقل طور پر TV غیر فعال کریں"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"فون کو مستقل طور پر غیر فعال کریں"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"‏براہ راست CDMA TV سیٹ اپ شروع کریں"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"‏CDMA فون سیٹ اپ کو براہ راست شروع کریں"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"‏ایپ کو CDMA فراہمی شروع کرنے کی اجازت دیتا ہے۔ نقصان دہ ایپس بغیر ضرورت کے CDMA فراہمی شروع کر سکتی ہیں۔"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"مقام کے اپ ڈیٹ کی اطلاعات کو کنٹرول کریں"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"ایپ کو ریڈیو سے مقام کی اپ ڈیٹ کی اطلاعات فعال کرنے/غیر فعال کرنے کی اجازت دیتا ہے۔ عام ایپس کے استعمال کیلئے نہیں ہے۔"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"چیک ان کی خصوصیات تک رسائی حاصل کریں"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"‏ایک ایپلیکیشن کو DRM سرٹیفکیٹس کو ہٹانے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہیں ہونی چاہیے۔"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"ایک کیریئر پیغام رسانی سروس کا پابند بنیں"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"حامل کو ایک کیریئر پیغام رسانی سروس کے اعلی سطحی انٹرفیس کا پابند ہونے کی اجازت دیتی ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہیں ہونی چاہیے۔"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"صوتی تعامل کی سروس کے ساتھ تعامل کریں"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"حامل کو موجودہ فعال صوتی تعامل کی سروس سے تعامل کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"پاس ورڈ کے اصول سیٹ کریں"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"‏اسکرین لاک پاس ورڈز اور PINs میں اجازت یافتہ لمبائی اور حروف کو کنٹرول کریں۔"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"اسکرین غیر مقفل کرنے کی کوششیں مانیٹر کریں"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ایپ کو اس بات کی توثیق کرنے کی اجازت دیتا ہے کہ پیکج انسٹال کرنے قابل ہے۔"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"پیکج کے ایک توثیق کار کے پابند بنیں"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"حامل کو پیکیج کے توثیق کاروں کی درخواستیں کرنے دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہيں ہونی چاہئے۔"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"انٹنٹ فلٹر کی توثیق کریں"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"ایپ کو یہ چیک کرنے کی اجازت دیتا ہے کہ آیا انٹنٹ فلٹر توثیق شدہ ہے یا نہیں۔"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"انٹنٹ فلٹر توثیق کار کے پابند بنیں"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"حامل کو انٹنٹ فلٹر کے توثیق کاروں کی درخواستیں کرنے کی اجازت دیتا ہے۔ عام ایپس کیلئے کبھی بھی اس کی ضرورت نہیں ہونی چاہیے۔"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"سیریل پورٹس تک رسائی حاصل کریں"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"‏SerialManager API کا استعمال کرکے حامل کو سیریل پورٹز تک رسائی دیتا ہے۔"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"مواد فراہم کنندگان تک خارجی رسائی حاصل کریں"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"دن گھٹائیں"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"سال بڑھائیں"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"سال گھٹائیں"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"پچھلا مہینہ"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"اگلا مہینہ"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"منسوخ کریں"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"حذف کریں"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"منٹ منتخب کریں"</string>
     <string name="select_day" msgid="7774759604701773332">"ماہ اور دن منتخب کریں"</string>
     <string name="select_year" msgid="7952052866994196170">"سال منتخب کریں"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> کو منتخب کیا گیا"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> کو حذف کر دیا گیا"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"دفتر <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"اس اسکرین سے پن ہٹانے کیلئے، واپس جائیں اور مجموعی جائزہ کو ایک ساتھ ٹچ کریں اور دبا کر رکھیں۔"</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"‏پن ہٹانے سے پہلے PIN طلب کریں"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"بیٹری کی میعاد بہتر کرنے میں مدد کرنے کیلئے، بیٹری کی بچت آپ کے آلہ کی کارکردگی کم کر دیتی ہے اور وائبریشن، مقام کی سروسز اور پس منظر کا بیشتر ڈیٹا محدود کر دیتی ہے۔ ای میل، پیغام رسانی اور مطابقت پذیری پر مبنی دیگر ایپس ممکن ہے اس وقت تک اپ ڈیٹ نہ ہوں جب تک آپ انہیں نہ کھولیں۔\n\nآپ کا آلہ چارج ہوتے وقت بیٹری کی بچت خود بخود آف ہو جاتی ہے۔"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"<xliff:g id="FORMATTEDTIME">%1$s</xliff:g> پر آپ کا آخری وقت ختم ہونے تک"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"آپ کا ڈاؤن ٹائم ختم ہونے تک"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index f0a6abb..1b4edb1 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Rouming banneri o‘chirilgan"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Xizmatlar qidirilmoqda"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi qo‘ng‘iroq"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"O‘chirilgan"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Wi-Fi afzal ko‘rilsin"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Mobil tarmoq afzal ko‘rilsin"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Faqat Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Yo‘naltirilmadi"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>  <xliff:g id="TIME_DELAY">{2}</xliff:g> soniyadan so‘ng"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"LED ko‘rsatkichni kamera faolligida boshqarish imkoniyatini o‘chirish"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Zavodda o‘rnatilgan tizim dasturiga kamerani o‘chirish uchun LED ko‘rsatkichidan foydalanish imkonini beradi."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Oldindan o‘rnatilgan tizimga oid ilovaga tizimdagi o‘zgarishlar bo‘yicha kamera xizmati bildirishnomalarini yuborish uchun ruxsat beradi."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"doimo planshetni o‘chirish"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"televizorni butunlay o‘chirib qo‘yish"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"doimo telefonni o‘chirish"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"bevosita CDMA televizorni sozlashni boshlash"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"CDMA telefonni moslashni to‘g‘ridan to‘g‘ri boshlash"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ilova CDMA sozlamasini ishga tushirishi mumkin. Zararli dasturlar uning yordamida zarurat bo‘lmaganda ham CDMA sozlamasini ishga tushirishi mumkin."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"SIM karta sozlashuvini boshlash"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Ilovaga SIM kartani faollashtirishga ruxsat beradi. Ilova sim kartani to‘g‘ridan-to‘g‘ri faollashtirishi yoki bu amalni boshqa ilovaga topshirihi mumkin."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"manzilni boshqarish yangiliklari eslatmalari"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ilova qabul qilish-uzatish moslamasi ma’lumotlari asosida joylashuvning yangilangani to‘g‘risidagi bildirishnomalarni yoqishi yoki o‘chirib qo‘yishi mumkin. Oddiy ilovalar tomonidan foydalanilmaydi."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"tasdiqdan o‘tib kirish xossalari"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Ilovaga DRM sertifikatlarini o‘chirib tashlash uchun ruxsat beradi. Oddiy ilovalar uchun talab qilinmaydi."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"aloqa operatorining xabar almashinuv xizmatiga bog‘lanish"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Egasiga aloqa operatorining xabar almashinuv xizmatining yuqori darajali interfeysiga bog‘lanish uchun ruxsat beradi. Oddiy ilovalar uchun hech qachon kerak bo‘lmaydi."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"ovozli muloqot xizmatidan foydalanish"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Egasiga joriy ovozli muloqot xizmatidan foydalanishga ruxsat beradi. Oddiy ilovalarda hech qachon kerak bo‘lmaydi."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Parol qoidalarini o‘rnatish"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Ekran qulfi paroli va PIN kodlari uchun qo‘yiladigan talablarni (belgilar soni va uzunligi) nazorat qiladi."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Ekranni qulfdan chiqarish urinishlarini nazorat qilish"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ilova paketlarni o‘rnatish imkoniyatini tekshirishi mumkin."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paketni tekshirgichga bog‘lash"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ilova paketlarni tekshirishni talab qilishi mumkin. Oddiy ilovalar uchun talab qilinmaydi."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"intent-filtrni tekshirish"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Ilovaga intent-filtr holatini tekshirish uchun ruxsat beradi."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"intent-filtrni tekshirgichga biriktirish"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Egasiga intent-filtr tekshiruvi so‘rovlarini yuborish uchun ruxsat beradi. Oddiy ilovalarda hech qachon kerak bo‘lmaydi."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"serial portlarga kirish"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Foydalanuvchiga SerialManager API’dan foydalanib, serial portlarga kirishga ruxsat beradi."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"kontent provayderiga tashqi ruxsat"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Kunni kamaytirish"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Yilni ko‘paytirish"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yilni kamaytirish"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Avvalgi oy"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Keyingi oy"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Bekor qilish"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"O‘chirish"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Daqiqalarni tanlash"</string>
     <string name="select_day" msgid="7774759604701773332">"Oy va kunni tanlash"</string>
     <string name="select_year" msgid="7952052866994196170">"Yilni tanlash"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"<xliff:g id="ITEM">%1$s</xliff:g> tanlandi"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> o‘chirildi"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Ish <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ushbu ekrandan chiqish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosib turing."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Bo‘shatishdan oldin PIN kod so‘ralsin"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Bo‘shatishdan oldin chizmali parol so‘ralsin"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Bo‘shatishdan oldin parol so‘ralsin"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Batareya quvvatini uzoqroq vaqtga yetkazish uchun quvvat tejash funksiyasi qurilmangiz unumdorligini kamaytiradi hamda uning tebranishi va orqa fonda internetdan foydalanishini cheklaydi. Sinxronlanishni talab qiladigan e-pochta, xabar almashinuv va boshqa ilovalar esa qachonki ularni ishga tushirganingizda yangilanadi.\n\nQurilma quvvat olayotganda quvvat tejash funksiyasi avtomatik tarzda o‘chadi."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Tanaffus vaqti tugaguncha – <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Nofoal vaqtingiz tugaguncha"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 73c2b67..6d84c90 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"Biểu ngữ Chuyển vùng Tắt"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Đang tìm kiếm Dịch vụ"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Gọi qua Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Không được chuyển tiếp"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> sau <xliff:g id="TIME_DELAY">{2}</xliff:g> giây"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"vô hiệu hóa tính năng phát đèn LED chỉ báo khi máy ảnh đang được sử dụng"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Cho phép cài đặt trước ứng dụng hệ thống để vô hiệu hóa việc máy ảnh sử dụng đèn LED chỉ báo."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Cho phép cài đặt trước ứng dụng hệ thống để gửi sự kiện về hệ thống dịch vụ máy ảnh."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"vô hiệu hóa vĩnh viễn máy tính bảng"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"tắt vĩnh viễn TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"vĩnh viễn vô hiệu hóa điện thoại"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"trực tiếp bắt đầu thiết lập TV CDMA"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"trực tiếp bắt đầu thiết lập điện thoại CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Cho phép ứng dụng bắt đầu cấp phép CDMA. Ứng dụng độc hại có thể bắt đầu cấp phép CDMA một cách không cần thiết."</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"kiểm soát thông báo cập nhật vị trí"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Cho phép ứng dụng bật/tắt thông báo cập nhật vị trí của radio. Không dành cho ứng dụng thông thường."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"truy cập thuộc tính đăng nhập"</string>
@@ -753,7 +768,7 @@
     <string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"Ngón tay đã di chuyển quá nhanh. Vui lòng thử lại."</string>
     <string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"Ngón tay đã di chuyển quá chậm. Vui lòng thử lại."</string>
   <string-array name="fingerprint_acquired_vendor">
-    <item msgid="2892952818207766996">"Thông báo lỗi lấy vân tay cho người bán cụ thể 0"</item>
+    <item msgid="2892952818207766996">"Thông báo lỗi lấy vân tay từ người bán cụ thể 0"</item>
   </string-array>
     <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"Không thể xử lý. Hãy thử lại."</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"Phần cứng không có sẵn."</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Cho phép ứng dụng xóa chứng chỉ DRM. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"liên kết với dịch vụ nhắn tin của nhà cung cấp dịch vụ"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Cho phép chủ sở hữu liên kết với giao diện cấp cao nhất của dịch vụ nhắn tin của nhà cung cấp dịch vụ. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"tương tác với dịch vụ tương tác bằng giọng nói"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Cho phép chủ sở hữu tương tác với dịch vụ tương tác bằng giọng nói hiện hoạt. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Đặt quy tắc mật khẩu"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kiểm soát độ dài và ký tự được phép trong mật khẩu khóa màn hình và mã PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Giám sát những lần thử mở khóa màn hình"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Cho phép ứng dụng xác minh gói có thể cài đặt."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"liên kết với trình xác minh gói"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"xác minh bộ lọc theo mục đích"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Cho phép ứng dụng kiểm tra xem bộ lọc theo mục đích đã được xác minh hay chưa."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"liên kết với trình xác minh bộ lọc theo mục đích"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Cho phép chủ sở hữu yêu cầu trình xác minh bộ lọc theo mục đích. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"truy cập vào nhà cung cấp nội dung từ bên ngoài"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Giảm ngày"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Tăng năm"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Giảm năm"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Tháng trước"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Tháng sau"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Hủy"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Xóa"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Chọn phút"</string>
     <string name="select_day" msgid="7774759604701773332">"Chọn tháng và ngày"</string>
     <string name="select_year" msgid="7952052866994196170">"Chọn năm"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"Đã chọn <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Đã xóa <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> làm việc"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Để bỏ khóa màn hình này, chạm và giữ Quay lại và Tổng quan cùng lúc."</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Hỏi mã PIN trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Hỏi hình mở khóa trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Hỏi mật khẩu trước khi bỏ ghim"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Để giúp tăng tuổi thọ pin, trình tiết kiệm pin sẽ giảm hiệu suất thiết bị của bạn và hạn chế rung, dịch vụ vị trí và hầu hết dữ liệu nền. Email, nhắn tin và các ứng dụng khác dựa trên đồng bộ hóa có thể không cập nhật nếu bạn không mở chúng.\n\nTrình tiết kiệm pin tự động tắt khi thiết bị của bạn đang sạc."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Cho tới khi thời gian ngừng hoạt động của bạn kết thúc vào <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Cho đến khi thời gian ngừng hoạt động kết thúc"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 63dd5c7..5139de8 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"禁用漫游横幅"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"正在搜索服务"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"WLAN 通话"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:无法转接"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g>秒后<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"在相机使用过程中停用传输指示灯 LED"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"允许预装的系统应用禁止相机使用指示灯 LED。"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"允许预装的系统应用发送相机服务系统事件。"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"永久停用平板电脑"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"永久停用电视"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"永久停用手机"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"直接启动 CDMA 电视设置"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"直接启动 CDMA 电话设置"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"允许应用启动 CDMA 配置。恶意应用可能会无端启动 CDMA 配置。"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"允许应用启用/停用来自无线装置的位置更新通知。普通应用不应使用此权限。"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"访问检入属性"</string>
@@ -761,7 +776,7 @@
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指纹录入操作超时,请重试。"</string>
     <string name="fingerprint_error_vendor" msgid="3175724710791609491">"指纹录入操作超时,请重试。"</string>
   <string-array name="fingerprint_error_vendor">
-    <item msgid="5804600450373644614">"针对供应商的错误消息"</item>
+    <item msgid="5804600450373644614">"针对供应商的错误消息。"</item>
   </string-array>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"读取同步设置"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允许该应用读取某个帐户的同步设置。例如,此权限可确定“联系人”应用是否与某个帐户同步。"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"允许应用移除DRM证书。普通应用绝不需要此权限。"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"绑定到运营商消息传递服务"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允许应用绑定到运营商消息传递服务的顶级接口。普通应用绝不需要此权限。"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"与语音互动服务进行互动"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"允许应用与当前启用的语音互动服务进行互动。普通应用绝不需要此权限。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"设置密码规则"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"控制锁屏密码和 PIN 码所允许的长度和字符。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"监视屏幕解锁尝试次数"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允许应用验证软件包是否可安装。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"绑定到软件包验证程序"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许应用申请使用软件包验证程序。普通应用绝不需要此权限。"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"验证 Intent 过滤器"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"允许该应用检查 Intent 过滤器是否已经过验证。"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"绑定至 Intent 过滤器验证程序"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"允许应用请求使用 Intent 过滤器验证程序。普通应用绝不需要此权限。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"允许应用通过SerialManager API使用串行端口。"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"从外部访问内容提供程序"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"减小日期值"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增大年份值"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"减小年份值"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"上个月"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"下个月"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"选择分钟"</string>
     <string name="select_day" msgid="7774759604701773332">"选择月份和日期"</string>
     <string name="select_year" msgid="7952052866994196170">"选择年份"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"已选择<xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"已删除<xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"工作<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"要取消固定此屏幕,请同时触摸并按住“返回”和“概览”按钮。"</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消时要求绘制解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消时要求输入密码"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"为了延长电池的续航时间,节电助手会降低设备的性能,并限制振动、位置信息服务和大部分后台流量。对于电子邮件、聊天工具等依赖于同步功能的应用,可能要打开这类应用时才能收到新信息。\n\n节电助手会在设备充电时自动关闭。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"直到休息时间结束(<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>)"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"到休息时间结束"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 4956a88..6ef00a3 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"漫遊橫幅關閉"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"正在搜尋服務"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi 通話"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"關閉"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"首選 Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"首選流動數據"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"只限 Wi-Fi"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:尚未轉接"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> 於 <xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後轉接"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"使用相機時停用傳輸指示燈"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"允許預先安裝的系統應用程式停用相機指示燈。"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"允許預先安裝的系統應用程式傳送相機服務系統活動。"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"永久停用平板電腦"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"永遠停用電視"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"永久停用手機"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"直接啟動 CDMA 電視設定"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"直接啟動 CDMA 手機設定程序"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"允許應用程式啟動 CDMA 佈建功能。惡意應用程式可能會在非必要的情況下啟動 CDMA 佈建功能。"</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"開始 SIM 卡設定"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"允許應用程式處理 SIM 啟動要求。該應用程式可能直接執行啟動或委託其他應用程式處理。"</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"允許應用程式啟用/停用來自無線電的位置更新通知 (不建議一般應用程式使用)。"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"存取登錄屬性"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"允許應用程式移除 DRM 憑證 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"繫結至流動網絡供應商短訊服務"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式繫結至流動網絡供應商短訊服務的頂層介面 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"與語音互動服務互動"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"允許應用程式與目前運作中的語音互動服務互動 (一般應用程式並不需要)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"控制螢幕鎖定密碼和 PIN 所允許的長度和字元。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監控螢幕解鎖嘗試次數"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證套件是否可安裝。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (不建議一般應用程式使用)。"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"驗證意圖篩選器"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"允許應用程式檢查意圖篩選器是否已通過驗證。"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"繫結至意圖篩選器驗證"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"允許應用程式要求驗證意圖篩選器 (不建議一般應用程式使用)。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"接入串列通訊埠"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 接入串列通訊埠。"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"從外部存取內容供應商"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"減少日數"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增加年數"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"減少年數"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"上個月"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"下個月"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"刪除"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"選取分鐘"</string>
     <string name="select_day" msgid="7774759604701773332">"選取月份和日期"</string>
     <string name="select_year" msgid="7952052866994196170">"選取年份"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"已選取<xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"<xliff:g id="KEY">%1$s</xliff:g> 已刪除"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住 [返回] 和 [概覽]。"</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"節約電池用量模式有助於延長電池壽命,但這會降低裝置效能,並限制震動、定位服務及大部分背景數據傳輸。除非您啟用,否則電郵、短訊及其他需要使用同步功能的應用程式均不會更新。\n\n當裝置充電時,節約電池用量模式會自動關閉。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"直到停機時間於 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 結束"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"直到停機時間完結"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 98c1cd2..e2d13dd 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -124,9 +124,19 @@
     <string name="roamingText12" msgid="1189071119992726320">"漫遊橫幅關閉"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"正在搜尋服務"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi 通話"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <!-- no translation found for wifi_calling_off_summary (8720659586041656098) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_preferred_summary (1994113411286935263) -->
+    <skip />
+    <!-- no translation found for wfc_mode_cellular_preferred_summary (5920549484600758786) -->
+    <skip />
+    <!-- no translation found for wfc_mode_wifi_only_summary (2379919155237869320) -->
+    <skip />
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:未轉接"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>:<xliff:g id="TIME_DELAY">{2}</xliff:g> 秒後 <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
@@ -585,6 +595,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"使用攝影機時停用傳輸指示器 LED"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"允許預先安裝的系統應用程式停用攝影機指示器 LED。"</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"允許預先安裝的系統應用程式傳送相機服務系統事件。"</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"永久停用平板電腦"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"永久停用電視"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"永久停用電話"</string>
@@ -633,6 +644,10 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"直接啟動 CDMA 電視設定程序"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"直接起始 CDMA 手機設定程序"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"允許應用程式啟動 CDMA 服務。請注意,惡意應用程式可能利用此功能啟動非必要的 CDMA 服務。"</string>
+    <!-- no translation found for permlab_performSimActivation (1651116521896665009) -->
+    <skip />
+    <!-- no translation found for permdesc_performSimActivation (1778214876348917401) -->
+    <skip />
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"允許應用程式啟用/停用來自無線電的位置更新通知 (不建議一般應用程式使用)。"</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"存取登機選項"</string>
@@ -753,7 +768,7 @@
     <string name="fingerprint_acquired_too_fast" msgid="5303368850245663580">"手指移動速度過快,請再試一次。"</string>
     <string name="fingerprint_acquired_too_slow" msgid="7381891107120721078">"手指移動速度過慢,請再試一次。"</string>
   <string-array name="fingerprint_acquired_vendor">
-    <item msgid="2892952818207766996">"供應商專用的指紋擷取錯誤訊息 0"</item>
+    <item msgid="2892952818207766996">"供應商自訂的指紋擷取錯誤訊息 0"</item>
   </string-array>
     <string name="fingerprint_error_unable_to_process" msgid="4232401562838100026">"無法辨識指紋,請再試一次。"</string>
     <string name="fingerprint_error_hw_not_available" msgid="6162709753784993771">"硬體無法使用。"</string>
@@ -761,7 +776,7 @@
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"指紋處理作業逾時,請再試一次。"</string>
     <string name="fingerprint_error_vendor" msgid="3175724710791609491">"指紋處理作業逾時,請再試一次。"</string>
   <string-array name="fingerprint_error_vendor">
-    <item msgid="5804600450373644614">"供應商專用的錯誤訊息。"</item>
+    <item msgid="5804600450373644614">"供應商自訂的錯誤訊息。"</item>
   </string-array>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"讀取同步處理設定"</string>
     <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string>
@@ -839,6 +854,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"允許應用程式移除 DRM 憑證 (一般應用程式並不需要)。"</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"與行動通訊業者簡訊服務繫結"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"允許應用程式與行動通訊業者簡訊服務的頂層介面繫結 (一般應用程式並不需要)。"</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"與語音互動服務互動"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"允許應用程式與目前啟用的語音互動服務互動 (一般應用程式並不需要)。"</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"設定密碼規則"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"管理螢幕鎖定密碼和 PIN 碼支援的字元和長度上限。"</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"監視螢幕解鎖嘗試次數"</string>
@@ -1136,6 +1153,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證是否可安裝特定套件。"</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"驗證用途篩選器"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"允許應用程式檢查用途篩選器是否已通過驗證。"</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"與用途篩選器驗證程式繫結"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"允許應用程式要求用途篩選器驗證程式 (一般應用程式不需使用)。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"從外部存取內容供應端"</string>
@@ -1561,6 +1582,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"減少日數"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"增加年數"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"減少年數"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"上個月"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"下個月"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt 鍵"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"取消"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete 鍵"</string>
@@ -1813,7 +1836,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"選取分鐘數"</string>
     <string name="select_day" msgid="7774759604701773332">"選取月份和日期"</string>
     <string name="select_year" msgid="7952052866994196170">"選取年份"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"已選取 <xliff:g id="ITEM">%1$s</xliff:g>"</string>
     <string name="deleted_key" msgid="7659477886625566590">"已刪除 <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"公司<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"如要取消固定這個畫面,請同時輕觸並按住返回按鈕和總覽按鈕。"</string>
@@ -1824,6 +1846,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消固定時必須輸入 PIN"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消固定時必須畫出解鎖圖形"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消固定時必須輸入密碼"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"節約耗電量模式會透過降低裝置效能、震動限制、定位服務限制和大多數背景資料運作限制等方式,延長電池續航力。此外,如果未開啟電子郵件、簡訊和其他需要使用同步功能的應用程式,系統將不會自動更新這些應用程式。\n\n當您為裝置充電時,節約耗電量模式會自動關閉。"</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"直到 <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> 停機時間結束"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"直到停機時間結束"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1833ece..aadf56b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -124,9 +124,15 @@
     <string name="roamingText12" msgid="1189071119992726320">"Ibhena yokuzulazula ivaliwe"</string>
     <string name="roamingTextSearching" msgid="8360141885972279963">"Iseshela Isevisi"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Ukushaya kwe-Wi-Fi"</string>
-  <string-array name="wfcOperatorErrorMessages">
+  <string-array name="wfcOperatorErrorAlertMessages">
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
   </string-array>
     <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Valiwe"</string>
+    <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Kuncanyelwa i-Wi-Fi"</string>
+    <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Kuncanyelwa iselula"</string>
+    <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"I-Wi-Fi kuphela"</string>
     <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: Akudlulisiwe"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> emuva kwamasekhondi angu-<xliff:g id="TIME_DELAY">{2}</xliff:g>"</string>
@@ -585,6 +591,7 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string>
     <string name="permlab_cameraDisableTransmitLed" msgid="2651072630501126222">"khubaza i-LED yesikhombi sokudlulisa uma ikhamera isebenza"</string>
     <string name="permdesc_cameraDisableTransmitLed" msgid="4764585465480295341">"Ivumela isistimu efakwe ngaphambili yohlelo lokusebenza ukuze ikhubaze i-LED yesikhombi sokusetshenziswa kwekhamera."</string>
+    <string name="permdesc_cameraSendSystemEvent" msgid="8642231538552298107">"Ivumela uhlelo lokusebenza lesistimu olufakwe ngaphambilini ukuthumela imicimbi yesistimu yesevisi yekhamera."</string>
     <string name="permlab_brick" product="tablet" msgid="2961292205764488304">"vimbela ngokuphelele ithebhulethi"</string>
     <string name="permlab_brick" product="tv" msgid="4912674222121249410">"khubaza unaphakade i-TV"</string>
     <string name="permlab_brick" product="default" msgid="8337817093326370537">"ngokwaphakade vimbela ifoni"</string>
@@ -633,6 +640,8 @@
     <string name="permlab_performCdmaProvisioning" product="tv" msgid="3485391974208100809">"qala ngokuqondile ukusethwa kwe-CDMA TV"</string>
     <string name="permlab_performCdmaProvisioning" product="default" msgid="5604848095315421425">"ngokuqondile qalisa ukumisa ifoni nge-CDMA"</string>
     <string name="permdesc_performCdmaProvisioning" msgid="1994193538802314186">"Ivumela uhlelo lokusebenza ukuqalisa amalungiselelo e-CDMA. Izuhlelo lokusebenza ezinobungozi ingaqalisa amalungiselelo e-CDMA ngokungenasidingo."</string>
+    <string name="permlab_performSimActivation" msgid="1651116521896665009">"qala ukusetha kwekhadi le-SIM"</string>
+    <string name="permdesc_performSimActivation" msgid="1778214876348917401">"Ivumela uhlelo lokusebenza ukuthi liphathe izicelo zokwenza i-SIM isebenze. Uhlelo lokusebenza lingenza ngokuqondile ukwenza kusebenze noma liphakele kwelinye uhlelo lokusebenza."</string>
     <string name="permlab_locationUpdates" msgid="7785408253364335740">"lawula izaziso zokubuyekeza indawo"</string>
     <string name="permdesc_locationUpdates" msgid="1120741557891438876">"Ivumela ukuthi uhlelo lokusebenza yenze izaziso zendawo zisebenze noma zingasebenzi emsakazweni. Ayenzelwe ukuthi isetshenziswe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_checkinProperties" msgid="7855259461268734914">"finyelela kwizakhiwo zokuhlola"</string>
@@ -839,6 +848,8 @@
     <string name="permdesc_removeDrmCertificates" msgid="7272999075113400993">"Ivumela uhlelo lokusebenza ukususa izitifiketi ze-DRM. Akufanele idingeke ngezinhlelo zokusebenza ezivamile."</string>
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"bophezela kusevisi yomlayezo yenkampani yenethiwekhi"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Ivumela isibambi ukuhlanganisa isixhumanisi sokubona esiphezulu sesevisi yomlayezo yenkampani yenethiwekhi. Akufanele idingeke kuzinhlelo zokusebenza ezivamile."</string>
+    <string name="permlab_accessVoiceInteractionService" msgid="4183835260471435605">"hlanganyela nesevisi ebandakanyayo yezwi"</string>
+    <string name="permdesc_accessVoiceInteractionService" msgid="836587728238433459">"Vumela umbambi ukuthi ahlanganyele nesevisi yamanje esebenzayo yezwi. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Misa imithetho yephasiwedi"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Lawula ubude nezinhlamvu ezivunyelwe kumaphasiwedi wokukhiya isikrini nama-PIN."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Gaka imizamo yokuvula isikrini"</string>
@@ -1136,6 +1147,10 @@
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string>
+    <string name="permlab_intentFilterVerificationAgent" msgid="1135788294400437497">"qinisekisa isihlungi esihlosiwe"</string>
+    <string name="permdesc_intentFilterVerificationAgent" msgid="5853902808424716312">"Ivumela uhlelo lokusebenza ukuthi lihlole uma ngabe isihlungi esihlosiwe siqinisekisiwe noma asiqinisekisiwe."</string>
+    <string name="permlab_bindIntentFilterVerifier" msgid="8567268159430779210">"hlanganisa kusiqinisekisi esihlosiwe sesihlungi"</string>
+    <string name="permdesc_bindIntentFilterVerifier" msgid="681128728719578778">"Ivumela umbambi ukuthi enze izicelo zeziqinisekisi ezihlosiwe zesihlungi. Akumele kudingelwe izinhlelo zokusebenza ezijwayelekile."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string>
     <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"finyelela abahlinzeki bokuqukethwe ngaphandle"</string>
@@ -1561,6 +1576,8 @@
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Yehlisa usuku"</string>
     <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Khulisa unyaka"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Yehlisa unyaka"</string>
+    <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Inyanga edlule"</string>
+    <string name="date_picker_next_month_button" msgid="5559507736887605055">"Inyanga ezayo"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"i-ALT"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Khansela"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Susa"</string>
@@ -1813,7 +1830,6 @@
     <string name="select_minutes" msgid="3974345615920336087">"Khetha amaminithi"</string>
     <string name="select_day" msgid="7774759604701773332">"Khetha inyanga nosuku"</string>
     <string name="select_year" msgid="7952052866994196170">"Khetha unyaka"</string>
-    <string name="item_is_selected" msgid="949687401682476608">"I-<xliff:g id="ITEM">%1$s</xliff:g> ekhethiwe"</string>
     <string name="deleted_key" msgid="7659477886625566590">"I-<xliff:g id="KEY">%1$s</xliff:g> isusiwe"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Umsebenzi <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="lock_to_app_toast" msgid="7570091317001980053">"Ukuze ususe ukuphina kulesi sikrini, thinta uphinde ubambe i-Emuva ne-Buka konke ngesikhathi esisodwa."</string>
@@ -1824,6 +1840,10 @@
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Cela iphinikhodi ngaphambi kokuphina"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Cela iphethini yokuvula ngaphambi kokususa ukuphina"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Cela iphasiwedi ngaphambi kokususa ukuphina"</string>
+    <!-- no translation found for package_installed_device_owner (8420696545959087545) -->
+    <skip />
+    <!-- no translation found for package_deleted_device_owner (7650577387493101353) -->
+    <skip />
     <string name="battery_saver_description" msgid="1960431123816253034">"Ukusiza ukuthuthukisa impilo yebhethri, isilondoloze sebhethri sehlisa ukusebenza kwedivayisi yakho futhi sikhawulele ukudlidliza, amasevisi wendawo, nedatha eningi yangasemuva. I-imeyili, imilayezo, nezinye izinhlelo zokusebenza ezincike ekuvumelaniseni zingahle zingabuyekezwa ngaphandle kokuthi uzivule.\n\nIsilondolozi sebhethri siyavaleka ngokuzenzakalelayo uma idivayisi yakho ishaja."</string>
     <string name="downtime_condition_summary" msgid="8761776337475705749">"Kuze kuphele isikhathi sakho ngo-<xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="downtime_condition_line_one" msgid="8762708714645352010">"Kuze kuphele isikhathi sakho sokuphumula"</string>
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 3312f4f..f6df01f 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -348,9 +348,9 @@
        <item>@drawable/progress_large_material</item>
        <item>@drawable/progress_medium_material</item>
        <item>@drawable/progress_small_material</item>
-       <item>@drawable/ratingbar_full_empty_material</item>
-       <item>@drawable/ratingbar_full_filled_material</item>
-       <item>@drawable/ratingbar_full_material</item>
+       <item>@drawable/ratingbar_material</item>
+       <item>@drawable/ratingbar_small_material</item>
+       <item>@drawable/ratingbar_indicator_material</item>
        <item>@drawable/scrollbar_handle_material</item>
        <item>@drawable/scrubber_control_material_anim</item>
        <item>@drawable/scrubber_control_selector_material</item>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dcb4b9e..cbd74cd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3414,9 +3414,9 @@
         <attr name="position">
             <!-- Floating at the top of the content. -->
             <enum name="floating" value="0" />
-            <!-- Pinned alongside the thumb. -->
+            <!-- Pinned to the thumb, vertically centered with the middle of the thumb. -->
             <enum name="atThumb" value="1" />
-            <!-- Pinned above the thumb. -->
+            <!-- Pinned to the thumb, vertically centered with the top edge of the thumb. -->
             <enum name="aboveThumb" value="2" />
         </attr>
         <attr name="textAppearance" />
@@ -3428,6 +3428,16 @@
         <attr name="minHeight" />
         <!-- Padding for the section header preview. -->
         <attr name="padding" />
+        <!-- Position of thumb in relation to the track. -->
+        <attr name="thumbPosition">
+            <!-- The thumb's midpoint is anchored to the track. At its
+                 extremes, the thumb will extend half-way outside the
+                 track. -->
+            <enum name="midpoint" value="0" />
+            <!-- The thumb is entirely inside the track. At its extremes,
+                 the thumb will be contained entirely within the track. -->
+            <enum name="inside" value="1" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="FrameLayout">
         <!-- Determines whether to measure all children or just those in
@@ -3505,15 +3515,29 @@
         <!-- Sets a drawable as the content of this ImageView. -->
         <attr name="src" format="reference|color" />
         <!-- Controls how the image should be resized or moved to match the size
-             of this ImageView. -->
+             of this ImageView.  See {@link android.widget.ImageView.ScaleType} -->
         <attr name="scaleType">
+            <!-- Scale using the image matrix when drawing. See  
+                 {@link android.widget.ImageView#setImageMatrix(Matrix)}. -->
             <enum name="matrix" value="0" />
+            <!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#FILL}. -->
             <enum name="fitXY" value="1" />
+            <!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#START}. -->
             <enum name="fitStart" value="2" />
+            <!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#CENTER}. -->
             <enum name="fitCenter" value="3" />
+            <!-- Scale the image using {@link android.graphics.Matrix.ScaleToFit#END}. -->
             <enum name="fitEnd" value="4" />
+            <!-- Center the image in the view, but perform no scaling. -->
             <enum name="center" value="5" />
+            <!-- Scale the image uniformly (maintain the image's aspect ratio) so both dimensions 
+                 (width and height) of the image will be equal to or larger than the corresponding
+                 dimension of the view (minus padding). The image is then centered in the view. -->
             <enum name="centerCrop" value="6" />
+            <!-- Scale the image uniformly (maintain the image's aspect ratio) so that both
+                 dimensions (width and height) of the image will be equal to or less than the
+                 corresponding dimension of the view (minus padding). The image is then centered in
+                 the view. -->
             <enum name="centerInside" value="7" />
         </attr>
         <!-- Set this to true if you want the ImageView to adjust its bounds
@@ -4283,6 +4307,15 @@
         <attr name="letterSpacing" />
         <!-- Font feature settings. -->
         <attr name="fontFeatureSettings" />
+        <!-- Break strategy (control over paragraph layout). -->
+        <attr name="breakStrategy">
+            <!-- Line breaking uses simple strategy. -->
+            <enum name="simple" value="0" />
+            <!-- Line breaking uses high-quality strategy, including hyphenation. -->
+            <enum name="high_quality" value="1" />
+            <!-- Line breaking stratgegy balances line lengths. -->
+            <enum name="balanced" value="2" />
+        </attr>
     </declare-styleable>
     <declare-styleable name="TextViewAppearance">
         <!-- Base text color, typeface, size, and style. -->
@@ -5948,6 +5981,19 @@
             <!-- values are colors, which are integers starting with "#". -->
             <enum name="colorType"   value="3" />
         </attr>
+        <!-- Defines whether the animation should adjust duration in order to achieve the same
+             perceived effects on different devices. -->
+        <attr name="durationScaleHint" >
+            <!-- Default value for scale hint. When set, duration will not be scaled.-->
+            <enum name="noScale" value="0"/>
+            <!-- This should be used when the animation's moving distance is proportional to screen,
+                 as the scaling is based on screen size. -->
+            <enum name="screen" value="1"/>
+            <!-- This is for animations that have a distance defined in dp, which will be the same
+                 across different devices. In this case, scaling is based on the physical distance
+                 per dp on the current device. -->
+            <enum name="dp" value="2"/>
+        </attr>
     </declare-styleable>
 
     <declare-styleable name="PropertyValuesHolder">
@@ -5961,6 +6007,9 @@
         <attr name="valueType" />
         <attr name="value" />
         <attr name="fraction" format="float" />
+        <!-- Defines a per-interval interpolator for this keyframe. This interpolator will be used
+             to interpolate between this keyframe and the previous keyframe.-->
+        <attr name="interpolator" />
     </declare-styleable>
 
     <!-- ========================== -->
@@ -7204,6 +7253,9 @@
              the component here for their recognition service. -->
         <attr name="recognitionService" format="string" />
         <attr name="settingsActivity" />
+        <!-- Flag indicating whether this voice interaction service is capable of handling the
+             assist gesture. -->
+        <attr name="supportsAssistGesture" format="boolean" />
     </declare-styleable>
 
     <!-- Use <code>voice-enrollment-application</code>
@@ -7759,6 +7811,8 @@
             <enum name="multi-select" value="4" />
             <enum name="integer" value="5" />
             <enum name="string" value="6" />
+            <enum name="bundle" value="7" />
+            <enum name="bundle_array" value="8" />
         </attr>
         <attr name="title" />
         <attr name="description" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index b0b4e3a..5ffe57e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1269,8 +1269,13 @@
     
     <!-- The <code>uses-permission</code> tag requests a
          {@link #AndroidManifestPermission &lt;permission&gt;} that the containing
-         package must be granted in order for it to operate correctly.
-         See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
+         package must be granted in order for it to operate correctly. For runtime
+         permissions, i.e. ones with <code>dangerous</code> protection level, on a
+         platform that supports runtime permissions, the permission will not be
+         granted until the app explicitly requests it at runtime and the user approves
+         the grant. You cannot request at runtime permissions that are not declared
+         as used in the manifest. See the
+         <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions.  Also available is a
          {@link android.Manifest.permission list of permissions} included
          with the base platform.
@@ -1289,14 +1294,6 @@
              of Android higher than the number given here, the permission will not
              be requested.  -->
         <attr name="maxSdkVersion" format="integer" />
-        <!--  Specify whether this permission is required for the application.
-              The default is true, meaning the application requires the
-              permission, and it must always be granted when it is installed.
-              If you set this to false, then in some cases the application may
-              be installed with it being granted the permission, and it will
-              need to request the permission later if it needs it.
-        <attr name="required" format="boolean" />
-        -->
     </declare-styleable>
 
     <!-- The <code>uses-configuration</code> tag specifies
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1b2e952..6d9bbae 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -471,6 +471,18 @@
     <!-- Wifi driver supports batched scan -->
     <bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
 
+    <!-- Idle Receive current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_idle_receive_cur_ma">1</integer>
+
+    <!-- Rx current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_active_rx_cur_ma">2</integer>
+
+    <!-- Tx current for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_tx_cur_ma">3</integer>
+
+    <!-- Operating volatage for wifi radio. 0 by default-->
+    <integer translatable="false" name="config_wifi_operating_voltage_mv">4</integer>
+
     <!-- Flag indicating whether the we should enable the automatic brightness in Settings.
          Software implementation will be used if config_hardware_auto_brightness_available is not set -->
     <bool name="config_automatic_brightness_available">false</bool>
@@ -2032,15 +2044,11 @@
     <!-- Enabled built-in zen mode condition providers -->
     <string-array translatable="false" name="config_system_condition_providers">
         <item>countdown</item>
-        <item>downtime</item>
-        <item>next_alarm</item>
+        <item>schedule</item>
     </string-array>
 
-    <!-- Show the next-alarm as a zen exit condition if it occurs in the next n hours. -->
-    <integer name="config_next_alarm_condition_lookahead_threshold_hrs">12</integer>
-
-    <!-- Show downtime as a zen exit condition if it starts in the next n hours. -->
-    <integer name="config_downtime_condition_lookahead_threshold_hrs">4</integer>
+    <!-- Priority repeat caller threshold, in minutes -->
+    <integer name="config_zen_repeat_callers_threshold">15</integer>
 
     <!-- Flags enabling default window features. See Window.java -->
     <bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 7d08e7f..2654a25 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -379,11 +379,11 @@
     <dimen name="text_handle_min_size">40dp</dimen>
 
     <!-- Lighting and shadow properties -->
-    <dimen name="light_y">-200dp</dimen>
-    <dimen name="light_z">800dp</dimen>
-    <dimen name="light_radius">600dp</dimen>
-    <item type="dimen" format="float" name="ambient_shadow_alpha">0.075</item>
-    <item type="dimen" format="float" name="spot_shadow_alpha">0.15</item>
+    <dimen name="light_y">0dp</dimen>
+    <dimen name="light_z">600dp</dimen>
+    <dimen name="light_radius">800dp</dimen>
+    <item type="dimen" format="float" name="ambient_shadow_alpha">0.039</item>
+    <item type="dimen" format="float" name="spot_shadow_alpha">0.19</item>
 
      <!-- Floating toolbar dimensions -->
      <dimen name="floating_toolbar_height">48dp</dimen>
@@ -392,4 +392,6 @@
      <dimen name="floating_toolbar_menu_button_minimum_width">48dp</dimen>
      <dimen name="floating_toolbar_default_width">250dp</dimen>
      <dimen name="floating_toolbar_minimum_overflow_height">192dp</dimen>
+     <dimen name="floating_toolbar_overflow_width">130dp</dimen>
+     <dimen name="floating_toolbar_margin">2dp</dimen>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 7e963954..aaf252a 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -93,5 +93,10 @@
   <item type="id" name="undo" />
   <item type="id" name="redo" />
   <item type="id" name="replaceText" />
-  <item type="id" name="accessibility_action_show_on_screen" />
+
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_ON_SCREEN}. -->
+  <item type="id" name="accessibilityActionShowOnScreen" />
+
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SCROLL_TO_POSITION}. -->
+  <item type="id" name="accessibilityActionScrollToPosition" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5c7daf2..c2f2c6d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2646,15 +2646,21 @@
   <public type="id" name="undo" />
   <public type="id" name="redo" />
   <public type="id" name="replaceText" />
+  <public type="id" name="accessibilityActionShowOnScreen" />
+  <public type="id" name="accessibilityActionScrollToPosition" />
 
   <public type="attr" name="allowUndo" />
-
   <public type="attr" name="colorBackgroundFloating" />
-
   <public type="attr" name="extractNativeLibs" />
   <public type="attr" name="usesCleartextTraffic" />
 
   <!--IntentFilter auto verification -->
   <public type="attr" name="autoVerify" />
+  <public type="attr" name="breakStrategy" />
 
+  <public type="attr" name="supportsAssistGesture" />
+  <public type="attr" name="thumbPosition" />
+
+  <!-- Animation -->
+  <public type="attr" name="durationScaleHint" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 702510a..e22d3b6 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -249,10 +249,20 @@
     <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
     <!-- WFC Operator Error Codes -->
     <string-array name="wfcOperatorErrorCodes" translatable="false" />
-    <!-- WFC Operator Error Messages -->
-    <string-array name="wfcOperatorErrorMessages" />
+    <!-- WFC Operator Error Messages showed as alerts -->
+    <string-array name="wfcOperatorErrorAlertMessages" />
+    <!-- WFC Operator Error Messages showed as notifications -->
+    <string-array name="wfcOperatorErrorNotificationMessages" />
     <!-- Template for showing cellular network operator name while WFC is active -->
     <string name="wfcSpnFormat">%s</string>
+    <!-- WFC, summary for Disabled -->
+    <string name="wifi_calling_off_summary">Off</string>
+    <!-- WFC, summary for Wi-Fi Preferred -->
+    <string name="wfc_mode_wifi_preferred_summary">Wi-Fi preferred</string>
+    <!-- WFC, summary for Cellular Preferred -->
+    <string name="wfc_mode_cellular_preferred_summary">Cellular preferred</string>
+    <!-- WFC, summary for Wi-Fi Only -->
+    <string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
 
     <!--
         {0} is one of "bearerServiceCode*"
@@ -519,19 +529,14 @@
     <string name="managed_profile_label">Work</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_costMoney">Services that cost you money</string>
+    <string name="permgrouplab_contacts">Contacts</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_costMoney">Do things that can cost you money.</string>
+    <string name="permgroupdesc_contacts">access and modify your contacts</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_messages">Your messages</string>
+    <string name="permgrouplab_location">Location</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_messages">Read and write your SMS, email, and other messages.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_personalInfo">Your personal information</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_personalInfo">Direct access to information about you, stored in on your contact card.</string>
+    <string name="permgroupdesc_location">access your location</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_socialInfo">Your social information</string>
@@ -539,141 +544,44 @@
     <string name="permgroupdesc_socialInfo">Direct access to information about your contacts and social connections.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_location">Your location</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_location">Monitor your physical location.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_network">Network communication</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_network">Access various network features.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_bluetoothNetwork">Bluetooth</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_bluetoothNetwork">Access devices and networks through Bluetooth.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_audioSettings">Audio Settings</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_audioSettings">Change audio settings.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_affectsBattery">Affects Battery</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_affectsBattery">Use features that can quickly drain battery.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_calendar">Calendar</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_calendar">Direct access to calendar and events.</string>
+    <string name="permgroupdesc_calendar">access and modify your calendar</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_dictionary">Read User Dictionary</string>
+    <string name="permgrouplab_sms">SMS</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_dictionary">Read words in user dictionary.</string>
+    <string name="permgroupdesc_sms">access and modify SMS</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_writeDictionary">Write User Dictionary</string>
+    <string name="permgrouplab_dictionary">User Dictionary</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_writeDictionary">Add words to the user dictionary.</string>
+    <string name="permgroupdesc_dictionary">Read or write words in user dictionary.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_bookmarks">Bookmarks and History</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgroupdesc_bookmarks">Direct access to bookmarks and browser history.</string>
 
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_deviceAlarms">Alarm</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_deviceAlarms">Set the alarm clock.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_voicemail">Voicemail</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_voicemail">Direct access to voicemail.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
+    <!-- Title of a category of application permissioncds, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_microphone">Microphone</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_microphone">Direct access to the microphone to record audio.</string>
+    <string name="permgroupdesc_microphone">use device microphone</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_camera">Camera</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_camera">Direct access to camera for image or video capture.</string>
+    <string name="permgroupdesc_camera">use device camera</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_screenlock">Lock screen</string>
+    <string name="permgrouplab_phone">Phone</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_screenlock">Ability to affect behavior of the lock screen on your device.</string>
+    <string name="permgroupdesc_phone">use device telephony</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_appInfo">Your applications information</string>
+    <string name="permgrouplab_sensors">Sensors</string>
     <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_appInfo">Ability to affect behavior of other applications on your device.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_wallpaper">Wallpaper</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_wallpaper">Change the device wallpaper settings.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_systemClock">Clock</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_systemClock">Change the device time or timezone.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_statusBar">Status Bar</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_statusBar">Change the device status bar settings.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_syncSettings">Sync Settings</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_syncSettings">Access to the sync settings.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_accounts">Your accounts</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_accounts">Access the available accounts.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_hardwareControls">Hardware controls</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_hardwareControls">Direct access to hardware on the handset.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_phoneCalls">Phone calls</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_phoneCalls">Monitor, record, and process phone calls.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_systemTools">System tools</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_systemTools">Lower-level access and control of the system.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_developmentTools">Development tools</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_developmentTools">Features only needed for app developers.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_display">Other Application UI</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_display">Effect the UI of other applications.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_storage">Storage</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this.   [CHAR LIMIT=30] -->
-    <string name="permgroupdesc_storage" product="nosdcard">Access the USB storage.</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_storage" product="default">Access the SD card.</string>
-
-    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgrouplab_accessibilityFeatures">Accessibility features</string>
-    <!-- Description of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permgroupdesc_accessibilityFeatures">Features that assistive technology can request.</string>
+    <string name="permgroupdesc_sensors">access sensors and wearables</string>
 
     <!-- Title for the capability of an accessibility service to retrieve window content. -->
     <string name="capability_title_canRetrieveWindowContent">Retrieve window content</string>
@@ -754,22 +662,6 @@
       messages. This means the app could monitor or delete messages sent to your
       device without showing them to you.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_receiveEmergencyBroadcast">receive emergency broadcasts</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_receiveEmergencyBroadcast">Allows the app to receive
-      and process emergency broadcast messages. This permission is only available
-      to system apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readCellBroadcasts">read cell broadcast messages</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readCellBroadcasts">Allows the app to read
-      cell broadcast messages received by your device. Cell broadcast alerts
-      are delivered in some locations to warn you of emergency situations.
-      Malicious apps may interfere with the performance or operation of your
-      device when an emergency cell broadcast is received.</string>
-
      <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_sendSms">send SMS messages</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -777,13 +669,6 @@
      This may result in unexpected charges. Malicious apps may cost you money by
      sending messages without your confirmation.</string>
 
-     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permlab_sendRespondViaMessageRequest">send respond-via-message events</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_sendRespondViaMessageRequest">Allows the app to send
-      requests to other messaging apps to handle respond-via-message events for incoming
-      calls.</string>
-
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readSms">read your text messages (SMS or MMS)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -822,13 +707,6 @@
      messages sent to you without showing them to you.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_receiveBluetoothMap">receive Bluetooth messages (MAP)</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_receiveBluetoothMap">Allows the app to receive and process Bluetooth MAP
-      messages. This means the app could monitor or delete messages sent to your
-      device without showing them to you.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getTasks">retrieve running apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getTasks">Allows the app to retrieve information
@@ -836,84 +714,11 @@
        discover information about which applications are used on the device.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_startTasksFromRecents">start a task from recents</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_startTasksFromRecents">Allows the app to use an ActivityManager.RecentTaskInfo
-        object to launch a defunct task that was returned from ActivityManager.getRecentTaskList().</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permlab_interactAcrossUsers">interact across users</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_interactAcrossUsers">Allows the app to perform actions
-        across different users on the device.  Malicious apps may use this to violate
-        the protection between users.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permlab_interactAcrossUsersFull">full license to interact across users</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_interactAcrossUsersFull">Allows all possible interactions across
-        users.</string>
-
-    <!--  Title of an application permission, listed so the user can choose whether they want to allow the application to create/remove/query users. [CHAR LIMIT=none] -->
-    <string name="permlab_manageUsers">manage users</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to create/remove/query users. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_manageUsers">Allows apps to manage users on the device, including query, creation and deletion.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=50] -->
-    <string name="permlab_getDetailedTasks">retrieve details of running apps</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_getDetailedTasks">Allows the app to retrieve
-        detailed information about currently and recently running tasks. Malicious apps may
-        discover private information about other apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_reorderTasks">reorder running apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_reorderTasks">Allows the app to move tasks to the
       foreground and background.  The app may do this without your input.</string>
 
-    <!-- Title of an application permission, allowing an application to remove/kill tasks -->
-    <string name="permlab_removeTasks">stop running apps</string>
-    <!-- Description of an application permission, allowing an application to remove/kill tasks -->
-    <string name="permdesc_removeTasks">Allows the app to remove
-        tasks and kill their apps. Malicious apps may disrupt
-        the behavior of other apps.</string>
-
-    <!-- [CHAR LIMIT=NONE] Title of an application permission, allowing an application to create,
-         change, remove activity stacks. -->
-    <string name="permlab_manageActivityStacks">manage activity stacks</string>
-    <!-- [CHAR LIMIT=NONE] Description of an application permission, allowing an application to create,
-             change, remove activity stacks. -->
-    <string name="permdesc_manageActivityStacks">Allows the app to add, remove, and
-        modify the activity stacks in which other apps run.  Malicious apps may disrupt
-        the behavior of other apps.</string>
-
-    <!-- Title of an application permission, allowing an application to start any activity, regardless of permission protection or exported state. -->
-    <string name="permlab_startAnyActivity">start any activity</string>
-    <!-- Description of an application permission, allowing an application to start any activity, regardless of permission protection or exported state. -->
-    <string name="permdesc_startAnyActivity">Allows the app to start any activity, regardless of permission protection or exported state.</string>
-
-    <!-- Title of an application permission, allowing control of app screen compatibility mode -->
-    <string name="permlab_setScreenCompatibility">set screen compatibility</string>
-    <!-- Description of an application permission, allowing control of app screen compatibility mode -->
-    <string name="permdesc_setScreenCompatibility">Allows the app to control the
-        screen compatibility mode of other applications.  Malicious applications may
-        break the behavior of other applications.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setDebugApp">enable app debugging</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setDebugApp">Allows the app to turn
-        on debugging for another app. Malicious apps may use this
-        to kill other apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_changeConfiguration">change system display settings</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_changeConfiguration">Allows the app to
-        change the current configuration, such as the locale or overall font
-        size.</string>
-
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_enableCarMode">enable car mode</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -928,176 +733,6 @@
       running.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_forceStopPackages">force stop other apps</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_forceStopPackages">Allows the app to forcibly stop other apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_forceBack">force app to close</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_forceBack">Allows the app to force any
-        activity that is in the foreground to close and go back.
-        Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_dump">retrieve system internal state</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_dump">Allows the app to retrieve
-        internal state of the system. Malicious apps may retrieve
-        a wide variety of private and secure information that they should
-        never normally need.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_retrieve_window_content">retrieve screen content</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_retrieve_window_content">Allows the app to retrieve
-        the content of the active window. Malicious apps may retrieve
-        the entire window content and examine all its text except passwords.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_temporary_enable_accessibility">temporary enable accessibility</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_temporary_enable_accessibility">Allows an application to temporarily
-         enable accessibility on the device. Malicious apps may enable accessibility without
-         user consent.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_retrieveWindowToken">retrieve window token</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_retrieveWindowToken">Allows an application to retrieve
-        the window token. Malicious apps may perfrom unauthorized interaction with
-        the application window impersonating the system.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_frameStats">retrieve frame statistics</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_frameStats">Allows an application to collect
-        frame statistics. Malicious apps may observe the frame statistics
-        of windows from other apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_filter_events">filter events</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_filter_events">Allows an application to register an input filter
-            which filters the stream of all user events before they are dispatched. Malicious app
-            may control the system UI whtout user intervention.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_shutdown">partial shutdown</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_shutdown">Puts the activity manager into a shutdown
-        state.  Does not perform a complete shutdown.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_stopAppSwitches">prevent app switches</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_stopAppSwitches">Prevents the user from switching to
-        another app.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_getTopActivityInfo">get current app info</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_getTopActivityInfo">Allows the holder to retrieve private information
-        about the current application in the foreground of the screen.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_runSetActivityWatcher">monitor and control all app launching</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_runSetActivityWatcher">Allows the app to
-        monitor and control how the system launches activities.
-        Malicious apps may completely compromise the system. This
-        permission is only needed for development, never for normal
-        use.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_broadcastPackageRemoved">send package removed broadcast</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_broadcastPackageRemoved">Allows the app to
-        broadcast a notification that an app package has been removed.
-        Malicious apps may use this to kill any other running
-        app.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_broadcastSmsReceived">send SMS-received broadcast</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_broadcastSmsReceived">Allows the app to
-        broadcast a notification that an SMS message has been received.
-        Malicious apps may use this to forge incoming SMS messages.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_broadcastWapPush">send WAP-PUSH-received broadcast</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_broadcastWapPush">Allows the app to
-        broadcast a notification that a WAP PUSH message has been received.
-        Malicious apps may use this to forge MMS message receipt or to
-        silently replace the content of any webpage with malicious variants.</string>
-
-    <!-- TODO: Mark these as translatable when API is finalized. -->
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_broadcastNetworkPrivileged" translatable="false">send privileged network broadcasts</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_broadcastNetworkPrivileged" translatable="false">Allows the app
-        to send privileged network broadcasts.
-        Never needed for normal apps.
-    </string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setProcessLimit">limit number of running processes</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setProcessLimit">Allows the app
-        to control the maximum number of processes that will run. Never
-        needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setAlwaysFinish">force background apps to close</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setAlwaysFinish">Allows the app
-        to control whether activities are always finished as soon as they
-        go to the background. Never needed for normal apps.</string>
-
-    <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_batteryStats">read battery statistics</string>
-    <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_batteryStats">Allows an application to read the current low-level
-        battery use data.  May allow the application to find out detailed information about
-        which apps you use.</string>
-
-    <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_updateBatteryStats">modify battery statistics</string>
-    <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_updateBatteryStats">Allows the app to modify
-        collected battery statistics. Not for use by normal apps.</string>
-
-    <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_getAppOpsStats">retrieve app ops statistics</string>
-    <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_getAppOpsStats">Allows the app to retrieve
-        collected application operation statistics. Not for use by normal apps.</string>
-
-    <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_updateAppOpsStats">modify app ops statistics</string>
-    <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_updateAppOpsStats">Allows the app to modify
-        collected application operation statistics. Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_backup">control system backup and restore</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_backup">Allows the app to control the system\'s backup and restore mechanism.  Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_confirm_full_backup">confirm a full backup or restore operation</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_confirm_full_backup">Allows the app to launch the full backup confirmation UI.  Not to be used by any app.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_internalSystemWindow">display unauthorized windows</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_internalSystemWindow">Allows the app to create
-        windows that are intended to be used by the internal system
-        user interface. Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_systemAlertWindow">draw over other apps</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_systemAlertWindow">Allows the app to draw on top of other
@@ -1106,177 +741,6 @@
         seeing in other applications.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setAnimationScale">modify global animation speed</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setAnimationScale">Allows the app to change
-        the global animation speed (faster or slower animations) at any time.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_manageAppTokens">manage app tokens</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_manageAppTokens">Allows the app to
-        create and manage their own tokens, bypassing their normal
-        Z-ordering. Should never be needed for normal apps.</string>
-
-    <!-- [CHAR LIMIT=NONE] Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_freezeScreen">freeze screen</string>
-    <!-- [CHAR LIMIT=NONE] Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_freezeScreen">Allows the application to temporarily freeze
-        the screen for a full-screen transition.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_injectEvents">press keys and control buttons</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_injectEvents" product="tablet">Allows the app to deliver
-        its own input events (key presses, etc.) to other apps. Malicious
-        apps may use this to take over the tablet.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_injectEvents" product="tv">Allows the app to deliver
-        its own input events (key presses, etc.) to other apps. Malicious
-        apps may use this to take over the TV.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_injectEvents" product="default">Allows the app to deliver
-        its own input events (key presses, etc.) to other apps. Malicious
-        apps may use this to take over the phone.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readInputState">record what you type and actions you take</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readInputState">Allows the app to watch the
-        keys you press even when interacting with another app (such
-        as typing a password). Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindInputMethod">bind to an input method</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindInputMethod">Allows the holder to bind to the top-level
-        interface of an input method. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindAccessibilityService">bind to an accessibility service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindAccessibilityService">Allows the holder to bind to the top-level
-        interface of an accessibility service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindPrintService">bind to a print service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindPrintService">Allows the holder to bind to the top-level
-        interface of a print service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose
-         whether they want to allow the application to do this. -->
-    <string name="permlab_bindPrintSpoolerService">bind to a print spooler service</string>
-    <!-- Description of an application permission, listed so the user can
-         choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindPrintSpoolerService">Allows the holder to bind to the top-level
-        interface of a print spooler service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindNfcService">bind to NFC service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindNfcService">Allows the holder to bind to applications
-        that are emulating NFC cards. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindTextService">bind to a text service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindTextService">Allows the holder to bind to the top-level
-        interface of a text service(e.g. SpellCheckerService). Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindVpnService">bind to a VPN service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindVpnService">Allows the holder to bind to the top-level
-        interface of a Vpn service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindWallpaper">bind to a wallpaper</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindWallpaper">Allows the holder to bind to the top-level
-        interface of a wallpaper. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindVoiceInteraction">bind to a voice interactor</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindVoiceInteraction">Allows the holder to bind to the top-level
-        interface of a voice interaction service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_manageVoiceKeyphrases">manage voice keyphrases</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_manageVoiceKeyphrases">Allows the holder to manage the keyphrases for voice hotword detection.
-        Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindRemoteDisplay">bind to a remote display</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindRemoteDisplay">Allows the holder to bind to the top-level
-        interface of a remote display. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindRemoteViews">bind to a widget service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindRemoteViews">Allows the holder to bind to the top-level
-        interface of a widget service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindRouteProvider">bind to a route provider service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindRouteProvider">Allows the holder to bind to any registered
-        route providers. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindDeviceAdmin">interact with a device admin</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindDeviceAdmin">Allows the holder to send intents to
-        a device administrator. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindTvInput">bind to a TV input</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindTvInput">Allows the holder to bind to the top-level
-        interface of a TV input. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_modifyParentalControls">modify parental controls</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_modifyParentalControls">Allows the holder to modify the system\'s
-        parental controls data. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_manageDeviceAdmins">add or remove a device admin</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_manageDeviceAdmins">Allows the holder to add or remove active device
-        administrators. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setOrientation">change screen orientation</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setOrientation">Allows the app to change
-        the rotation of the screen at any time. Should never be needed for
-        normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_setPointerSpeed">change pointer speed</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_setPointerSpeed">Allows the app to change
-        the mouse or trackpad pointer speed at any time. Should never be needed for
-        normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_setKeyboardLayout">change keyboard layout</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_setKeyboardLayout">Allows the app to change
-        the keyboard layout. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_signalPersistentProcesses">send Linux signals to apps</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_signalPersistentProcesses">Allows the app to request that the
-        supplied signal be sent to all persistent processes.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_persistentActivity">make app always run</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_persistentActivity" product="tablet">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the tablet.</string>
@@ -1285,153 +749,17 @@
     <string name="permdesc_persistentActivity" product="default">Allows the app to make parts of itself persistent in memory.  This can limit memory available to other apps slowing down the phone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_deletePackages">delete apps</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_deletePackages">Allows the app to delete
-        Android packages. Malicious apps may use this to delete important apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_clearAppUserData">delete other apps\' data</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_clearAppUserData">Allows the app to clear user data.</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_deleteCacheFiles">delete other apps\' caches</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_deleteCacheFiles">Allows the app to delete
-        cache files.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getPackageSize">measure app storage space</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getPackageSize">Allows the app to retrieve its code, data, and cache sizes</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_installPackages">directly install apps</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_installPackages">Allows the app to install new or updated
-        Android packages. Malicious apps may use this to add new apps with arbitrarily
-        powerful permissions.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_clearAppCache">delete all app cache data</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_clearAppCache" product="tablet">Allows the app to free tablet storage
-        by deleting files in the cache directories of other applications.  This may cause other
-        applications to start up more slowly as they need to re-retrieve their data.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_clearAppCache" product="tv">Allows the app to free TV storage
-        by deleting files in the cache directories of other applications.  This may cause other
-        applications to start up more slowly as they need to re-retrieve their data.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_clearAppCache" product="default">Allows the app to free phone storage
-        by deleting files in the cache directories of other applications.  This may cause other
-        applications to start up more slowly as they need to re-retrieve their data.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_movePackage">move app resources</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_movePackage">Allows the app to move app resources from internal to external media and vice versa.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readLogs">read sensitive log data</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readLogs" product="tablet">Allows the app to read from the
-        system\'s various log files.  This allows it to discover general
-        information about what you are doing with the tablet, potentially
-        including personal or private information.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readLogs" product="tv">Allows the app to read from the
-        system\'s various log files.  This allows it to discover general
-        information about what you are doing with the TV, potentially
-        including personal or private information.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readLogs" product="default">Allows the app to read from the
-        system\'s various log files.  This allows it to discover general
-        information about what you are doing with the phone, potentially
-        including personal or private information.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_anyCodecForPlayback">use any media decoder for playback</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_anyCodecForPlayback">Allows the app to use any installed
-        media decoder to decode for playback.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. This permission allows the app to install or uninstall trusted credentials, a.k.a. CA certificates. [CHAR LIMIT=NONE] -->
-    <string name="permlab_manageCaCertificates">manage trusted credentials</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE]-->
-    <string name="permdesc_manageCaCertificates">Allows the app to install and uninstall CA certificates as trusted credentials.</string>
-
-    <!-- Title of a permission that is never presented to the user.  This is not a
-         permission that an application must be granted by the user.  Instead, it
-         is part of a mechanism that applications use to indicate to the system
-         that they want to do scheduled background work.  -->
-    <string name="permlab_bindJobService">run the application\'s scheduled background work</string>
-    <!-- Description of an application permission, so that the user can understand
-         what is being done if they are curious. -->
-    <string name="permdesc_bindJobService">This permission allows the Android system to run the application in the background when requested.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_diagnostic">read/write to resources owned by diag</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_diagnostic">Allows the app to read and write to
-    any resource owned by the diag group; for example, files in /dev. This could
-    potentially affect system stability and security. This should be ONLY be used
-    for hardware-specific diagnostics by the manufacturer or operator.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_changeComponentState">enable or disable app components</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_changeComponentState" product="tablet">Allows the app to change whether a
-        component of another app is enabled or not. Malicious apps may use this
-        to disable important tablet capabilities. Care must be used with this permission, as it is
-        possible to get app components into an unusable, inconsistent, or unstable state.
-    </string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_changeComponentState" product="tv">Allows the app to change whether a
-        component of another app is enabled or not. Malicious apps may use this
-        to disable important TV capabilities. Care must be used with this permission, as it is
-        possible to get app components into an unusable, inconsistent, or unstable state.
-    </string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_changeComponentState" product="default">Allows the app to change whether a
-        component of another app is enabled or not. Malicious apps may use this
-        to disable important phone capabilities. Care must be used with this permission, as it is
-        possible to get app components into an unusable, inconsistent, or unstable state.
-    </string>
-
-    <!-- Title of an application permission for granting or revoking other permissions [CHAR LIMIT=NONE] -->
-    <string name="permlab_grantRevokePermissions">grant or revoke permissions</string>
-    <!-- Description of an application permission for granting or revoking other permissions [CHAR LIMIT=NONE] -->
-    <string name="permdesc_grantRevokePermissions">Allows an application to grant or revoke
-        specific permissions for it or other applications.  Malicious applications may use this
-        to access features you have not granted them.
-    </string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setPreferredApplications">set preferred apps</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setPreferredApplications">Allows the app to
-        modify your preferred apps. Malicious apps may
-        silently change the apps that are run, spoofing your
-        existing apps to collect private data from you.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_writeSettings">modify system settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_writeSettings">Allows the app to modify the
         system\'s settings data. Malicious apps may corrupt your system\'s
         configuration.</string>
 
-    <string name="permlab_writeSecureSettings">modify secure system settings</string>
-    <string name="permdesc_writeSecureSettings">Allows the app to modify the
-        system\'s secure settings data. Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_writeGservices">modify the Google services map</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeGservices">Allows the app to modify the
-        Google services map.  Not for use by normal apps.</string>
-
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_receiveBootCompleted">run at startup</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1636,16 +964,8 @@
     <string name="permlab_accessLocationExtraCommands">access extra location provider commands</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessLocationExtraCommands">Allows the app to access
-      extra location provider commands.  This may allow the app to interfere
-      with the operation of the GPS or other location sources.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_installLocationProvider">permission to install a location provider</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_installLocationProvider">Create mock location sources
-      for testing or install a new location provider.  This allows the app to
-      override the location and/or status returned by other location sources
-      such as GPS or location providers.</string>
+        extra location provider commands.  This may allow the app to interfere
+        with the operation of the GPS or other location sources.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessFineLocation">precise location (GPS and
@@ -1669,69 +989,7 @@
       use them. Apps may use this to determine approximately where you
       are.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessSurfaceFlinger">access SurfaceFlinger</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessSurfaceFlinger">Allows the app to use SurfaceFlinger low-level features.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readFrameBuffer">read frame buffer</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readFrameBuffer">Allows the app to read the content of the frame buffer.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessInputFlinger">access InputFlinger</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessInputFlinger">Allows the app to use InputFlinger low-level features.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_configureWifiDisplay">configure Wifi displays</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_configureWifiDisplay">Allows the app to configure and connect to Wifi displays.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_controlWifiDisplay">control Wifi displays</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_controlWifiDisplay">Allows the app to control low-level features of Wifi displays.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_controlVpn">control Virtual Private Networks</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_controlVpn">Allows the app to control low-level features of Virtual Private Networks.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_captureAudioOutput">capture audio output</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_captureAudioOutput">Allows the app to capture and redirect audio output.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_captureAudioHotword">Hotword detection</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_captureAudioHotword">Allows the app to capture audio for Hotword detection. The capture can
-      happen in the background but does not prevent other audio capture (e.g. Camcorder).</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_modifyAudioRouting">Audio Routing</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_modifyAudioRouting">Allows the app to directly control audio routing and
-      override audio policy decisions.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_captureVideoOutput">capture video output</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_captureVideoOutput">Allows the app to capture and redirect video output.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_captureSecureVideoOutput">capture secure video output</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_captureSecureVideoOutput">Allows the app to capture and redirect secure video output.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_mediaContentControl">control media playback and metadata access</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_mediaContentControl">Allows the app to control media playback and access the media information (title, author...).</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_modifyAudioSettings">change your audio settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_modifyAudioSettings">Allows the app to modify global audio settings such as volume and which speaker is used for output.</string>
@@ -1754,80 +1012,6 @@
     <string name="permdesc_camera">Allows the app to take pictures and videos
       with the camera.  This permission allows the app to use the camera at any
       time without your confirmation.</string>
-    <!-- Title of a camera app permission, listed so the user can choose whether or not they want to allow it to disable the may-transmit light indicator. -->
-    <string name="permlab_cameraDisableTransmitLed">disable transmit indicator LED when camera is in use</string>
-    <!-- Description of a camera app permission, listed so the user can choose whether or not they want to allow it to disable the may-transmit light indicator. -->
-    <string name="permdesc_cameraDisableTransmitLed">Allows a pre-installed system application to disable the camera use indicator LED.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_brick" product="tablet">permanently disable tablet</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_brick" product="tv">permanently disable TV</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_brick" product="default">permanently disable phone</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_brick" product="tablet">Allows the app to
-        disable the entire tablet permanently. This is very dangerous.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_brick" product="tv">Allows the app to
-        disable the entire TV permanently. This is very dangerous.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_brick" product="default">Allows the app to
-        disable the entire phone permanently. This is very dangerous.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_reboot" product="tablet">force tablet reboot</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_reboot" product="tv">force TV reboot</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_reboot" product="default">force phone reboot</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_reboot" product="tablet">Allows the app to force the tablet to reboot.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_reboot" product="tv">Allows the app to force the TV to reboot.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_reboot" product="default">Allows the app to force the phone to reboot.</string>
-
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_mount_unmount_filesystems" product="nosdcard">access USB storage filesystem</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_mount_unmount_filesystems" product="default">access SD Card filesystem</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_mount_unmount_filesystems">Allows the app to mount and
-        unmount filesystems for removable storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_mount_format_filesystems" product="nosdcard">erase USB storage</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_mount_format_filesystems" product="default">erase SD Card</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_mount_format_filesystems">Allows the app to format removable storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_asec_access">get information on internal storage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_asec_access">Allows the app to get information on internal storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_asec_create">create internal storage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_asec_create">Allows the app to create internal storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_asec_destroy">destroy internal storage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_asec_destroy">Allows the app to destroy internal storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_asec_mount_unmount">mount/unmount internal storage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_asec_mount_unmount">Allows the app to mount/unmount internal storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_asec_rename">rename internal storage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_asec_rename">Allows the app to rename internal storage.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_vibrate">control vibration</string>
@@ -1840,27 +1024,6 @@
     <string name="permdesc_flashlight">Allows the app to control the flashlight.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_manageUsb">manage preferences and permissions for USB devices</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_manageUsb">Allows the app to manage preferences and permissions for USB devices.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessMtp">implement MTP protocol</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessMtp">Allows access to the kernel MTP driver to implement the MTP USB protocol.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_hardware_test">test hardware</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_hardware_test">Allows the app to control
-        various peripherals for the purpose of hardware testing.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_fm">access FM radio</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_fm">Allows the app to access FM radio to listen to programs.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_callPhone">directly call phone numbers</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_callPhone">Allows the app to call phone numbers
@@ -1870,53 +1033,6 @@
       confirmation.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_callPrivileged">directly call any phone numbers</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_callPrivileged">Allows the app to call
-        any phone number, including emergency numbers, without your intervention.
-        Malicious apps may place unnecessary and illegal calls to emergency
-        services.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_performCdmaProvisioning" product="tablet">directly start CDMA tablet setup</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_performCdmaProvisioning" product="tv">directly start CDMA TV setup</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_performCdmaProvisioning" product="default">directly start CDMA phone setup</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_performCdmaProvisioning">Allows the app to start CDMA provisioning.
-        Malicious apps may unnecessarily start CDMA provisioning.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_locationUpdates">control location update notifications</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_locationUpdates">Allows the app to enable/disable location
-        update notifications from the radio.  Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_checkinProperties">access checkin properties</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_checkinProperties">Allows the app read/write access to
-        properties uploaded by the checkin service.  Not for use by normal
-        apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindGadget">choose widgets</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindGadget">Allows the app to tell the system
-        which widgets can be used by which app. An app with this permission
-        can give access to personal data to other apps.
-        Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_modifyPhoneState">modify phone state</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_modifyPhoneState">Allows the app to control the
-        phone features of the device. An app with this permission can switch
-        networks, turn the phone radio on and off and the like without ever notifying
-        you.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readPhoneState">read phone status and identity</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readPhoneState">Allows the app to access the phone
@@ -1925,14 +1041,6 @@
       connected by a call.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readPrecisePhoneState">read precise phone states</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readPrecisePhoneState">Allows the app to access the precise
-      phone states.  This permission allows the app to determine the real
-      call status, whether a call is active or in the background, call fails,
-      precise data connection status and data connection fails.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tablet">prevent tablet from sleeping</string>
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_wakeLock" product="tv">prevent TV from sleeping</string>
@@ -1954,42 +1062,6 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_transmitIr" product="default">Allows the app to use the phone\'s infrared transmitter.</string>
 
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_devicePower" product="tablet">power tablet on or off</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_devicePower" product="tv">power TV on or off</string>
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_devicePower" product="default">power phone on or off</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_devicePower" product="tablet">Allows the app to turn the
-        tablet on or off.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_devicePower" product="tv">Allows the app to turn the
-        TV on or off.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_devicePower" product="default">Allows the app to turn the phone on or off.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_userActivity">reset display timeout</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_userActivity">Allows the app to reset the display timeout.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_factoryTest">run in factory test mode</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_factoryTest" product="tablet">Run as a low-level manufacturer test,
-        allowing complete access to the tablet hardware. Only available
-        when a tablet is running in manufacturer test mode.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_factoryTest" product="tv">Run as a low-level manufacturer test,
-        allowing complete access to the TV hardware. Only available
-        when a TV is running in manufacturer test mode.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_factoryTest" product="default">Run as a low-level manufacturer test,
-        allowing complete access to the phone hardware. Only available
-        when a phone is running in manufacturer test mode.</string>
-
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setWallpaper">set wallpaper</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2001,22 +1073,6 @@
     <string name="permdesc_setWallpaperHints">Allows the app to set the system wallpaper size hints.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_masterClear">reset system to factory defaults</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_masterClear">Allows the app to completely
-        reset the system to its factory settings, erasing all data,
-        configuration, and installed apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_setTime">set time</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setTime" product="tablet">Allows the app to change the tablet\'s clock time.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setTime" product="tv">Allows the app to change the TV\'s clock time.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setTime" product="default">Allows the app to change the phone\'s clock time.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_setTimeZone">set time zone</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_setTimeZone" product="tablet">Allows the app to change the tablet\'s time zone.</string>
@@ -2026,11 +1082,6 @@
     <string name="permdesc_setTimeZone" product="default">Allows the app to change the phone\'s time zone.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accountManagerService">act as the AccountManagerService</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accountManagerService">Allows the app to make calls to AccountAuthenticators.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_getAccounts">find accounts on the device</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_getAccounts" product="tablet">Allows the app to get
@@ -2045,6 +1096,7 @@
       the list of accounts known by the phone.  This may include any accounts
       created by applications you have installed.</string>
 
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_authenticateAccounts">create accounts and set passwords</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2080,14 +1132,7 @@
      applications provide means to send data to the internet, so this
      permission is not required to send data to the internet.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_writeApnSettings">change/intercept network settings and traffic</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_writeApnSettings">Allows the app to change network settings and to intercept and inspect all network traffic,
-      for example to change the proxy and port of any APN. Malicious apps may monitor, redirect, or modify network
-      packets without your knowledge.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_changeNetworkState">change network connectivity</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_changeNetworkState">Allows the app to change the state of network connectivity.</string>
@@ -2098,11 +1143,6 @@
     <string name="permdesc_changeTetherState">Allows the app to change the state of tethered network connectivity.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_changeBackgroundDataSetting">change background data usage setting</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_changeBackgroundDataSetting">Allows the app to change the background data usage setting.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_accessWifiState">view Wi-Fi connections</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessWifiState">Allows the app to view information
@@ -2130,7 +1170,7 @@
       packets sent to all devices on a Wi-Fi network using multicast addresses,
       not just your phone.  It uses more power than the non-multicast mode.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetoothAdmin">access Bluetooth settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetoothAdmin" product="tablet">Allows the app to
@@ -2144,27 +1184,6 @@
     <string name="permdesc_bluetoothAdmin" product="default">Allows the app to configure
       the local Bluetooth phone, and to discover and pair with remote devices.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bluetoothPriv">allow Bluetooth pairing by Application</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bluetoothPriv" product="tablet">Allows the app to
-      pair with remote devices without user interaction.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bluetoothPriv" product="tv">Allows the app to
-      pair with remote devices without user interaction.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bluetoothPriv" product="default">Allows the app to
-      pair with remote devices without user interaction.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bluetoothMap">access Bluetooth MAP data</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bluetoothMap" product="tablet">Allows the app to access Bluetooth MAP data.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bluetoothMap" product="tv">Allows the app to access Bluetooth MAP data.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bluetoothMap" product="default">Allows the app to access Bluetooth MAP data.</string>
-
     <string name="permlab_accessWimaxState">connect and disconnect from WiMAX</string>
     <string name="permdesc_accessWimaxState">Allows the app to determine whether
      WiMAX is enabled and information about any WiMAX networks that are
@@ -2178,19 +1197,7 @@
     <string name="permdesc_changeWimaxState" product="default">Allows the app to
       connect the phone to and disconnect the phone from WiMAX networks.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_scoreNetworks">score networks</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_scoreNetworks" product="tablet">Allows the app to
-      rank networks and influence which networks the tablet should prefer.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_scoreNetworks" product="tv">Allows the app to
-      rank networks and influence which networks the TV should prefer.</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_scoreNetworks" product="default">Allows the app to
-        rank networks and influence which networks the phone should prefer.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_bluetooth">pair with Bluetooth devices</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_bluetooth" product="tablet">Allows the app to view the
@@ -2274,17 +1281,6 @@
     <string name="permdesc_readSyncStats">Allows an app to read the sync stats for an account, including the history of sync events and how much data is synced. </string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_subscribedFeedsRead">read subscribed feeds</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_subscribedFeedsRead">Allows the app to get details about the currently synced feeds.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_subscribedFeedsWrite">write subscribed feeds</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_subscribedFeedsWrite">Allows the app to modify
-      your currently synced feeds. Malicious apps may change your synced feeds.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readDictionary">read terms you added to the dictionary</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readDictionary">Allows the app to read all words,
@@ -2314,138 +1310,12 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_sdcardWrite" product="default">Allows the app to write to the SD card.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_mediaStorageWrite" product="default">modify/delete internal media storage contents</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_mediaStorageWrite" product="default">Allows the app to modify the contents of the internal media storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_manageDocs" product="default">manage document storage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_manageDocs" product="default">Allows the app to manage document storage.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=30] -->
-    <string name="permlab_sdcardAccessAll">access external storage of all users</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_sdcardAccessAll">Allows the app to access external storage for all users.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_cache_filesystem">access the cache filesystem</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_cache_filesystem">Allows the app to read and write the cache filesystem.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_use_sip">make/receive SIP calls</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_use_sip">Allows the app to make and receive SIP calls.</string>
 
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_register_sim_subscription">register new telecom SIM connections</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_register_sim_subscription">Allows the app to register new telecom SIM connections.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_register_call_provider">register new telecom connections</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_register_call_provider">Allows the app to register new telecom connections.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_connection_manager">manage telecom connections</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_connection_manager">Allows the app to manage telecom connections.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bind_incall_service">interact with in-call screen</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bind_incall_service">Allows the app to control when and how the user sees the in-call screen.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bind_connection_service">interact with telephony services</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bind_connection_service">Allows the app to interact with telephony services to make/receive calls.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_control_incall_experience">provide an in-call user experience</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_control_incall_experience">Allows the app to provide an in-call user experience.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_readNetworkUsageHistory">read historical network usage</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_readNetworkUsageHistory">Allows the app to read historical network usage for specific networks and apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_manageNetworkPolicy">manage network policy</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_manageNetworkPolicy">Allows the app to manage network policies and define app-specific rules.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_modifyNetworkAccounting">modify network usage accounting</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_modifyNetworkAccounting">Allows the app to modify how network usage is accounted against apps. Not for use by normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessNotifications">access notifications</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessNotifications">Allows the app to retrieve, examine, and clear notifications, including those posted by other apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindNotificationListenerService">bind to a notification listener service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindChooserTargetService">bind to a chooser target service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindChooserTargetService">Allows the holder to bind to the top-level interface of a chooser target service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindConditionProviderService">bind to a condition provider service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindConditionProviderService">Allows the holder to bind to the top-level interface of a condition provider service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindMediaRouteService">bind to a media route service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindMediaRouteService">Allows the holder to bind to the top-level interface of a media route service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindDreamService">bind to a dream service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindDreamService">Allows the holder to bind to the top-level interface of a dream service. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_invokeCarrierSetup">invoke the carrier-provided configuration app</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_invokeCarrierSetup">Allows the holder to invoke the carrier-provided configuration app. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessNetworkConditions">listen for observations on network conditions</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessNetworkConditions">Allows an application to listen for observations on network conditions. Should never be needed for normal apps.</string>
-
-    <string name="permlab_setInputCalibration">change input device calibration</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_setInputCalibration">Allows the app to modify the calibration parameters of the touch screen. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessDrmCertificates">access DRM certificates</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_accessDrmCertificates">Allows an application to provision and use DRM certficates. Should never be needed for normal apps.</string>
-
-    <string name="permlab_handoverStatus">Receive Android Beam transfer status</string>
-    <string name="permdesc_handoverStatus">Allows this application to receive information about current Android Beam transfers</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_removeDrmCertificates">remove DRM certificates</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_removeDrmCertificates">Allows an application to remove DRM certficates. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_bindCarrierMessagingService">bind to a carrier messaging service</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_bindCarrierMessagingService">Allows the holder to bind to the top-level interface of a carrier messaging service. Should never be needed for normal apps.</string>
-
     <!-- Policy administration -->
 
     <!-- Title of policy access to limiting the user's password choices -->
@@ -3310,22 +2180,13 @@
         applications with web browsing capabilities.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether
-        they want to allow the application to do this. -->
+    they want to allow the application to do this. -->
     <string name="permlab_setAlarm">set an alarm</string>
     <!-- Description of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
     <string name="permdesc_setAlarm">Allows the app to set an alarm in
-      an installed alarm clock app. Some alarm clock apps may
-      not implement this feature.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether
-        they want to allow the application to modify and remove voicemails in the user's voicemail
-        inbox. [CHAR LIMIT=NONE] -->
-    <string name="permlab_writeVoicemail">write voicemails</string>
-    <!-- Description of an application permission, listed so the user can choose whether
-        they want to allow the application to modify and remove voicemails in the user's voicemail
-        inbox. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_writeVoicemail">Allows the app to modify and remove messages from your voicemail inbox.</string>
+        an installed alarm clock app. Some alarm clock apps may
+        not implement this feature.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether
         they want to allow the application to do this. [CHAR LIMIT=NONE] -->
@@ -3336,13 +2197,6 @@
       to your voicemail inbox.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether
-        they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permlab_readVoicemail">read voicemail</string>
-    <!-- Description of an application permission, listed so the user can choose whether
-        they want to allow the application to do this. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_readVoicemail">Allows the app to read your voicemails.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
     <string name="permlab_writeGeolocationPermissions">modify Browser geolocation permissions</string>
     <!-- Description of an application permission, listed so the user can choose whether
@@ -3351,55 +2205,6 @@
         Browser\'s geolocation permissions. Malicious apps
         may use this to allow sending location information to arbitrary web sites.</string>
 
-    <!-- Title of an application permission which allows the application to verify whether
-         a different package is able to be installed by some internal logic. [CHAR LIMIT=40] -->
-    <string name="permlab_packageVerificationAgent">verify packages</string>
-    <!-- Description of an application permission which allows the application to verify whether
-         a different package is able to be installed by some internal heuristic. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_packageVerificationAgent">Allows the app to verify a package is
-        installable.</string>
-
-    <!-- Title of an application permission which allows the application to verify whether
-         a different package is able to be installed by some internal heuristic. [CHAR LIMIT=40] -->
-    <string name="permlab_bindPackageVerifier">bind to a package verifier</string>
-    <!-- Description of an application permission which allows the application to verify whether
-         a different package is able to be installed by some internal heuristic. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bindPackageVerifier">Allows the holder to make requests of
-        package verifiers. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission which allows the application to verify whether
-         a different intent filter is able to be verified by some internal logic. [CHAR LIMIT=40] -->
-    <string name="permlab_intentFilterVerificationAgent">verify intent filter</string>
-    <!-- Description of an application permission which allows the application to verify whether
-         a different intent filter is able to be verified by some internal heuristic. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_intentFilterVerificationAgent">Allows the app to check if an intent filter
-        is verified or not.</string>
-
-    <!-- Title of an application permission which allows the application to verify whether
-         a different intent filter is able to be verified by some internal logic. [CHAR LIMIT=40] -->
-    <string name="permlab_bindIntentFilterVerifier">bind to an intent filter verifier</string>
-    <!-- Description of an application permission which allows the application to verify whether
-         a different intent filter is able to be verified by some internal logic. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_bindIntentFilterVerifier">Allows the holder to make requests of
-        intent filter verifiers. Should never be needed for normal apps.</string>
-
-    <!-- Title of an application permission which allows the application to access serial ports via the SerialManager. [CHAR LIMIT=40] -->
-    <string name="permlab_serialPort">access serial ports</string>
-    <!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_serialPort">Allows the holder to access serial ports using the SerialManager API.</string>
-
-    <!-- Title of an application permission which allows the holder to access content
-         providers from outside an ApplicationThread. [CHAR LIMIT=40] -->
-    <string name="permlab_accessContentProvidersExternally">access content providers externally</string>
-    <!-- Description of an application permission which allows the holder to access
-         content providers from outside an ApplicationThread. [CHAR LIMIT=NONE] -->
-    <string name="permdesc_accessContentProvidersExternally">Allows the holder to access content
-     providers from the shell. Should never be needed for normal apps.</string>
-    <!-- Title of an application permission which allows the application to suggest that now is a bad time to reboot the device in order to apply an OTA.  [CHAR LIMIT=40] -->
-    <string name="permlab_updateLock">discourage automatic device updates</string>
-    <!-- Description of an application permission which allows the application to suggest that now is a bad time to reboot the device in order to apply an OTA.  [CHAR LIMIT=NONE] -->
-    <string name="permdesc_updateLock">Allows the holder to offer information to the system about when would be a good time for a noninteractive reboot to upgrade the device.</string>
-
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
@@ -4118,61 +2923,11 @@
     <!-- Shown in LauncherActivity when the requested target Intent didn't return any matching Activities, leaving the list empty. -->
     <string name="activity_list_empty">No matching activities found.</string>
 
-    <!-- permission attributes related to package usage statistics -->
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_pkgUsageStats">update component usage statistics</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_pkgUsageStats">Allows the app to modify collected component usage statistics. Not for use by normal apps.</string>
-
-    <!-- permission attributes related to default container service -->
-    <!-- Title of an application permission that lets an application use default container service. -->
-    <string name="permlab_copyProtectedData">copy content</string>
-    <!-- Description of an application permission,  used to invoke default container service to copy content. -->
-    <string name="permdesc_copyProtectedData">Allows the app to invoke default container service to copy content. Not for use by normal apps.</string>
-
     <!-- Title of an application permission that lets an application route media output. -->
     <string name="permlab_route_media_output">Route media output</string>
     <!-- Description of an application permission that lets an application route media output. -->
     <string name="permdesc_route_media_output">Allows an application to route media output to other external devices.</string>
 
-    <!-- Title of an application permission that lets an application access keyguard secure storage. -->
-    <string name="permlab_access_keyguard_secure_storage">Access keyguard secure storage</string>
-    <!-- Description of an application permission that lets an application access keyguard secure storage. -->
-    <string name="permdesc_access_keyguard_secure_storage">Allows an application to access keguard secure storage.</string>
-
-    <!-- Title of an application permission that lets it control keyguard. -->
-    <string name="permlab_control_keyguard">Control displaying and hiding keyguard</string>
-    <!-- Description of an application permission that lets it control keyguard. -->
-    <string name="permdesc_control_keyguard">Allows an application to control keguard.</string>
-
-    <!-- Title of an application permission that lets it listen to trust state changes. -->
-    <string name="permlab_trust_listener">Listen to trust state changes.</string>
-    <!-- Description of an application permission that lets it listen to trust state changes. -->
-    <string name="permdesc_trust_listener">Allows an application to listen for changes in trust state.</string>
-
-    <!-- Title of an application permission that lets it provide a trust agent. -->
-    <string name="permlab_provide_trust_agent">Provide a trust agent.</string>
-    <!-- Description of an application permission that lets it provide a trust agent. -->
-    <string name="permdesc_provide_trust_agent">Allows an application to provide a trust agent.</string>
-    <!-- Title of an application permission that lets it launch the trust agent settings menu -->
-    <string name="permlab_launch_trust_agent_settings">Launch trust agent settings menu.</string>
-    <!-- Description of an application permission that lets it launch the trust agent settings menu -->
-    <string name="permdesc_launch_trust_agent_settings">Allows an application to launch an activity that changes the trust agent behavior.</string>
-    <!-- Title of an application permission that lets it bind to a trust agent service. -->
-    <string name="permlab_bind_trust_agent_service">Bind to a trust agent service</string>
-    <!-- Description of an application permission that lets it bind to a trust agent service. -->
-    <string name="permdesc_bind_trust_agent_service">Allows an application to bind to a trust agent service.</string>
-
-    <!-- Title of an application permission that lets it interact with recovery. -->
-    <string name="permlab_recovery">Interact with update and recovery system</string>
-    <!-- Description of an application permission that lets it control keyguard. -->
-    <string name="permdesc_recovery">Allows an application to interact with the recovery system and system updates.</string>
-
-    <!-- Title of an application permission that lets it manage media projection sessions. -->
-    <string name="permlab_manageMediaProjection">Manage media projection sessions</string>
-    <!-- Description of an application permission that lets it manage media projection sessions. -->
-    <string name="permdesc_manageMediaProjection">Allows an application to manage media projection sessions. These sessions can provide applications the ability to capture display and audio contents. Should never be needed by normal apps.</string>
-
     <!-- Title of an application permission that lets it read install sessions. -->
     <string name="permlab_readInstallSessions">Read install sessions</string>
     <!-- Description of an application permission that lets it read install sessions. -->
@@ -5141,15 +3896,14 @@
     <!-- Lock-to-app unlock password string -->
     <string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
 
+    <!-- Notification shown when device owner silently installs a package -->
+    <string name="package_installed_device_owner">Installed by your administrator</string>
+    <!-- Notification shown when device owner silently deletes a package -->
+    <string name="package_deleted_device_owner">Deleted by your administrator</string>
+
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
     <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
 
-    <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
-    <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
-
-    <!-- [CHAR_LIMIT=NONE] Zen mode: Condition line one for built-in downtime condition, if active -->
-    <string name="downtime_condition_line_one">Until your downtime ends</string>
-
     <!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_minutes_summary">
         <item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
@@ -5180,14 +3934,23 @@
     <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] -->
     <string name="zen_mode_forever">Until you turn this off</string>
 
+    <!-- Zen mode active automatic rule name separator. [CHAR LIMIT=NONE] -->
+    <string name="zen_mode_rule_name_combination"><xliff:g id="first" example="Weeknights">%1$s</xliff:g> / <xliff:g id="rest" example="Meetings">%2$s</xliff:g></string>
+
     <!-- Content description for the Toolbar icon used to collapse an expanded action mode. [CHAR LIMIT=NONE] -->
     <string name="toolbar_collapse_description">Collapse</string>
 
-    <!-- Zen mode condition - summary: until next alarm. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_next_alarm_summary">Until next alarm at <xliff:g id="formattedTime" example="7:30 AM">%1$s</xliff:g></string>
+    <!-- Zen mode - feature name. [CHAR LIMIT=40] -->
+    <string name="zen_mode_feature_name">Block interruptions</string>
 
-    <!-- Zen mode condition - line one: until next alarm. [CHAR LIMIT=NONE] -->
-    <string name="zen_mode_next_alarm_line_one">Until next alarm</string>
+    <!-- Zen mode - downtime legacy feature name. [CHAR LIMIT=40] -->
+    <string name="zen_mode_downtime_feature_name">Downtime</string>
+
+    <!-- Zen mode - name of default automatic schedule for weeknights. [CHAR LIMIT=40] -->
+    <string name="zen_mode_default_weeknights_name">Weeknights</string>
+
+    <!-- Zen mode - name of default automatic schedule for weekends. [CHAR LIMIT=40] -->
+    <string name="zen_mode_default_weekends_name">Weekends</string>
 
     <!-- Indication that the current volume and other effects (vibration) are being suppressed by a third party, such as a notification listener. [CHAR LIMIT=30] -->
     <string name="muted_by">Muted by <xliff:g id="third_party">%1$s</xliff:g></string>
@@ -5206,9 +3969,17 @@
     <string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
     <string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
 
+    <!-- User visible name for USB MIDI Peripheral port -->
+    <string name="usb_midi_peripheral_name">Android USB Peripheral Port</string>
     <!-- Manufacturer name for USB MIDI Peripheral port -->
     <string name="usb_midi_peripheral_manufacturer_name">Android</string>
-    <!-- Model name for USB MIDI Peripheral port -->
-    <string name="usb_midi_peripheral_model_name">USB Peripheral Port</string>
+    <!-- Product name for USB MIDI Peripheral port -->
+    <string name="usb_midi_peripheral_product_name">USB Peripheral Port</string>
+
+    <!-- Floating toolbar strings -->
+    <!-- Content description for the button that opens the floating toolbar overflow. [CHAR LIMIT=NONE] -->
+    <string name="floating_toolbar_open_overflow_description">More options</string>
+    <!-- Content description for the button that closes the floating toolbar overflow. [CHAR LIMIT=NONE] -->
+    <string name="floating_toolbar_close_overflow_description">Close overflow</string>
 
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index cc64b43..3c3d286 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -497,6 +497,7 @@
         <item name="textEditSideNoPasteWindowLayout">?attr/textEditSideNoPasteWindowLayout</item>
         <item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
         <item name="textCursorDrawable">?attr/textCursorDrawable</item>
+        <item name="breakStrategy">high_quality</item>
     </style>
 
     <style name="Widget.CheckedTextView">
@@ -527,6 +528,7 @@
         <item name="textAppearance">?attr/textAppearanceMediumInverse</item>
         <item name="textColor">?attr/editTextColor</item>
         <item name="gravity">center_vertical</item>
+        <item name="breakStrategy">simple</item>
     </style>
 
     <style name="Widget.ExpandableListView" parent="Widget.ListView">
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 9cf7884..88cac72 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -726,22 +726,22 @@
     </style>
 
     <style name="Widget.Material.RatingBar" parent="Widget.RatingBar">
-        <item name="progressDrawable">@drawable/ratingbar_full_material</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_full_material</item>
+        <item name="progressDrawable">@drawable/ratingbar_material</item>
+        <item name="indeterminateDrawable">@drawable/ratingbar_material</item>
     </style>
 
     <style name="Widget.Material.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
-        <item name="progressDrawable">@drawable/ratingbar_holo_dark</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_holo_dark</item>
-        <item name="minHeight">35dip</item>
-        <item name="maxHeight">35dip</item>
+        <item name="progressDrawable">@drawable/ratingbar_indicator_material</item>
+        <item name="indeterminateDrawable">@drawable/ratingbar_indicator_material</item>
+        <item name="minHeight">36dp</item>
+        <item name="maxHeight">36dp</item>
     </style>
 
     <style name="Widget.Material.RatingBar.Small" parent="Widget.RatingBar.Small">
-        <item name="progressDrawable">@drawable/ratingbar_small_holo_dark</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_dark</item>
-        <item name="minHeight">16dip</item>
-        <item name="maxHeight">16dip</item>
+        <item name="progressDrawable">@drawable/ratingbar_small_material</item>
+        <item name="indeterminateDrawable">@drawable/ratingbar_small_material</item>
+        <item name="minHeight">16dp</item>
+        <item name="maxHeight">16dp</item>
     </style>
 
     <style name="Widget.Material.ScrollView" parent="Widget.ScrollView"/>
@@ -943,9 +943,10 @@
         <item name="thumbMinWidth">0dp</item>
         <item name="thumbMinHeight">0dp</item>
         <item name="textSize">45sp</item>
-        <item name="minWidth">88dp</item>
+        <item name="minWidth">104dp</item>
         <item name="minHeight">88dp</item>
         <item name="padding">0dp</item>
+        <item name="thumbPosition">inside</item>
     </style>
 
     <style name="Widget.Material.PreferenceFrameLayout">
@@ -1038,22 +1039,9 @@
     <style name="Widget.Material.Light.ProgressBar.Small.Inverse" parent="Widget.Material.ProgressBar.Small.Inverse"/>
     <style name="Widget.Material.Light.ProgressBar.Large.Inverse" parent="Widget.Material.ProgressBar.Large.Inverse"/>
     <style name="Widget.Material.Light.SeekBar" parent="Widget.Material.SeekBar"/>
-    <style name="Widget.Material.Light.RatingBar" parent="Widget.Material.RatingBar" />
-
-    <style name="Widget.Material.Light.RatingBar.Indicator" parent="Widget.RatingBar.Indicator">
-        <item name="progressDrawable">@drawable/ratingbar_holo_light</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_holo_light</item>
-        <item name="minHeight">35dip</item>
-        <item name="maxHeight">35dip</item>
-    </style>
-
-    <style name="Widget.Material.Light.RatingBar.Small" parent="Widget.RatingBar.Small">
-        <item name="progressDrawable">@drawable/ratingbar_small_holo_light</item>
-        <item name="indeterminateDrawable">@drawable/ratingbar_small_holo_light</item>
-        <item name="minHeight">16dip</item>
-        <item name="maxHeight">16dip</item>
-    </style>
-
+    <style name="Widget.Material.Light.RatingBar" parent="Widget.Material.RatingBar"/>
+    <style name="Widget.Material.Light.RatingBar.Indicator" parent="Widget.Material.RatingBar.Indicator"/>
+    <style name="Widget.Material.Light.RatingBar.Small" parent="Widget.Material.RatingBar.Small"/>
     <style name="Widget.Material.Light.ScrollView" parent="Widget.Material.ScrollView"/>
     <style name="Widget.Material.Light.HorizontalScrollView" parent="Widget.Material.HorizontalScrollView"/>
     <style name="Widget.Material.Light.Spinner" parent="Widget.Material.Spinner" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 19352c9..42d187d 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -328,6 +328,10 @@
   <java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
   <java-symbol type="string"  name="config_wifi_random_mac_oui" />
   <java-symbol type="integer"  name="config_wifi_network_switching_blacklist_time" />
+  <java-symbol type="integer"  name="config_wifi_idle_receive_cur_ma" />
+  <java-symbol type="integer"  name="config_wifi_active_rx_cur_ma" />
+  <java-symbol type="integer"  name="config_wifi_tx_cur_ma" />
+  <java-symbol type="integer"  name="config_wifi_operating_voltage_mv" />
 
   <java-symbol type="bool" name="editable_voicemailnumber" />
 
@@ -690,6 +694,8 @@
   <java-symbol type="string" name="lock_to_app_unlock_pin" />
   <java-symbol type="string" name="lock_to_app_unlock_pattern" />
   <java-symbol type="string" name="lock_to_app_unlock_password" />
+  <java-symbol type="string" name="package_installed_device_owner" />
+  <java-symbol type="string" name="package_deleted_device_owner" />
   <java-symbol type="string" name="lockscreen_access_pattern_cell_added" />
   <java-symbol type="string" name="lockscreen_access_pattern_cleared" />
   <java-symbol type="string" name="lockscreen_access_pattern_detected" />
@@ -759,8 +765,13 @@
   <java-symbol type="string" name="phoneTypeWorkPager" />
   <java-symbol type="string" name="wfcRegErrorTitle" />
   <java-symbol type="array" name="wfcOperatorErrorCodes" />
-  <java-symbol type="array" name="wfcOperatorErrorMessages" />
+  <java-symbol type="array" name="wfcOperatorErrorAlertMessages" />
+  <java-symbol type="array" name="wfcOperatorErrorNotificationMessages" />
   <java-symbol type="string" name="wfcSpnFormat" />
+  <java-symbol type="string" name="wifi_calling_off_summary" />
+  <java-symbol type="string" name="wfc_mode_wifi_preferred_summary" />
+  <java-symbol type="string" name="wfc_mode_cellular_preferred_summary" />
+  <java-symbol type="string" name="wfc_mode_wifi_only_summary" />
   <java-symbol type="string" name="policydesc_disableCamera" />
   <java-symbol type="string" name="policydesc_encryptedStorage" />
   <java-symbol type="string" name="policydesc_expirePassword" />
@@ -1163,6 +1174,7 @@
   <java-symbol type="drawable" name="ic_audio_vol" />
   <java-symbol type="drawable" name="ic_audio_vol_mute" />
   <java-symbol type="drawable" name="ic_bullet_key_permission" />
+  <java-symbol type="drawable" name="ic_check_circle_24px" />
   <java-symbol type="drawable" name="ic_contact_picture" />
   <java-symbol type="drawable" name="ic_dialog_usb" />
   <java-symbol type="drawable" name="ic_emergency" />
@@ -2025,19 +2037,18 @@
   <java-symbol type="dimen" name="timepicker_text_size_normal" />
   <java-symbol type="dimen" name="timepicker_text_size_inner" />
   <java-symbol type="string" name="battery_saver_description" />
-  <java-symbol type="string" name="downtime_condition_summary" />
-  <java-symbol type="string" name="downtime_condition_line_one" />
   <java-symbol type="string" name="zen_mode_forever" />
+  <java-symbol type="string" name="zen_mode_rule_name_combination" />
   <java-symbol type="plurals" name="zen_mode_duration_minutes" />
   <java-symbol type="plurals" name="zen_mode_duration_hours" />
   <java-symbol type="plurals" name="zen_mode_duration_minutes_summary" />
   <java-symbol type="plurals" name="zen_mode_duration_hours_summary" />
   <java-symbol type="string" name="zen_mode_until" />
-  <java-symbol type="string" name="zen_mode_next_alarm_summary" />
-  <java-symbol type="string" name="zen_mode_next_alarm_line_one" />
+  <java-symbol type="string" name="zen_mode_feature_name" />
+  <java-symbol type="string" name="zen_mode_downtime_feature_name" />
+  <java-symbol type="string" name="zen_mode_default_weeknights_name" />
+  <java-symbol type="string" name="zen_mode_default_weekends_name" />
   <java-symbol type="array" name="config_system_condition_providers" />
-  <java-symbol type="integer" name="config_next_alarm_condition_lookahead_threshold_hrs" />
-  <java-symbol type="integer" name="config_downtime_condition_lookahead_threshold_hrs" />
   <java-symbol type="string" name="muted_by" />
 
   <java-symbol type="string" name="select_day" />
@@ -2170,8 +2181,9 @@
   <java-symbol type="bool" name="config_LTE_eri_for_network_name" />
   <java-symbol type="bool" name="config_defaultInTouchMode" />
 
+  <java-symbol type="string" name="usb_midi_peripheral_name" />
   <java-symbol type="string" name="usb_midi_peripheral_manufacturer_name" />
-  <java-symbol type="string" name="usb_midi_peripheral_model_name" />
+  <java-symbol type="string" name="usb_midi_peripheral_product_name" />
 
   <java-symbol type="bool" name="allow_stacked_button_bar" />
   <java-symbol type="id" name="spacer" />
@@ -2198,18 +2210,20 @@
   <java-symbol type="string" name="storage_sd_card" />
   <java-symbol type="string" name="storage_usb" />
 
-  <java-symbol type="id" name="accessibility_action_show_on_screen" />
-
   <!-- Floating toolbar -->
   <java-symbol type="layout" name="floating_popup_container" />
   <java-symbol type="layout" name="floating_popup_menu_button" />
   <java-symbol type="layout" name="floating_popup_open_overflow_button" />
+  <java-symbol type="layout" name="floating_popup_close_overflow_button" />
+  <java-symbol type="layout" name="floating_popup_overflow_list_item" />
   <java-symbol type="dimen" name="floating_toolbar_height" />
   <java-symbol type="dimen" name="floating_toolbar_menu_button_side_padding" />
   <java-symbol type="dimen" name="floating_toolbar_text_size" />
   <java-symbol type="dimen" name="floating_toolbar_menu_button_minimum_width" />
   <java-symbol type="dimen" name="floating_toolbar_default_width" />
   <java-symbol type="dimen" name="floating_toolbar_minimum_overflow_height" />
+  <java-symbol type="dimen" name="floating_toolbar_overflow_width" />
+  <java-symbol type="dimen" name="floating_toolbar_margin" />
 
   <java-symbol type="drawable" name="ic_chevron_left" />
   <java-symbol type="drawable" name="ic_chevron_right" />
@@ -2217,4 +2231,5 @@
   <java-symbol type="string" name="date_picker_next_month_button" />
   <java-symbol type="layout" name="date_picker_month_item_material" />
   <java-symbol type="id" name="month_view" />
+  <java-symbol type="integer" name="config_zen_repeat_callers_threshold" />
 </resources>
diff --git a/core/res/res/xml/default_zen_mode_config.xml b/core/res/res/xml/default_zen_mode_config.xml
index 1bdc1ec..5f4199a 100644
--- a/core/res/res/xml/default_zen_mode_config.xml
+++ b/core/res/res/xml/default_zen_mode_config.xml
@@ -18,7 +18,6 @@
 -->
 
 <!-- Default configuration for zen mode.  See android.service.notification.ZenModeConfig. -->
-<zen version="1">
-    <allow calls="false" messages="false" />
-    <sleep startHour="22" startMin="0" endHour="7" endMin="0" />
+<zen version="2">
+    <allow calls="true" messages="false" reminders="true" events="true" />
 </zen>
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index bfaea8f..b07d338 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -113,6 +113,9 @@
     <application android:theme="@style/Theme">
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" android:required="false" />
+        <meta-data
+            android:name="android.content.APP_RESTRICTIONS"
+            android:resource="@xml/app_restrictions" />
         <activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index ce0d9a2..04b0478 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -135,4 +135,8 @@
     <string name="first">Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.</string>
     <string name="actor">Abe Lincoln</string>
     <string name="caption">Lincoln adressing the crowd at Gettysburgh</string>
+
+    <!-- RestrictionsManagerTest -->
+    <string name="restrictionManager_title">Title</string>
+    <string name="restrictionManager_desc">Description</string>
 </resources>
diff --git a/core/tests/coretests/res/xml/app_restrictions.xml b/core/tests/coretests/res/xml/app_restrictions.xml
new file mode 100644
index 0000000..c84cabcc
--- /dev/null
+++ b/core/tests/coretests/res/xml/app_restrictions.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<restrictions xmlns:android="http://schemas.android.com/apk/res/android">
+    <restriction android:key="hidden_key"
+                 android:restrictionType="hidden"/>
+    <restriction
+            android:defaultValue="true"
+            android:description="@string/restrictionManager_desc"
+            android:key="bool_key"
+            android:restrictionType="bool"
+            android:title="@string/restrictionManager_title"/>
+    <restriction
+            android:defaultValue="test"
+            android:key="string_key"
+            android:restrictionType="string"/>
+
+    <restriction android:key="int_key"
+                 android:restrictionType="integer"
+                 android:defaultValue="15"/>
+    <restriction android:key="bundle_key"
+                 android:restrictionType="bundle">
+        <restriction
+                android:key="bundle_string_key"
+                android:restrictionType="string"/>
+        <restriction
+                android:defaultValue="true"
+                android:key="bundle_bool_key"
+                android:restrictionType="bool"/>
+
+    </restriction>
+    <restriction android:key="bundle_array_key"
+                 android:restrictionType="bundle_array">
+        <restriction android:key="bundle_array_int"
+                     android:restrictionType="integer"/>
+        <restriction android:key="bundle_array_bundle_key"
+                     android:restrictionType="bundle">
+            <restriction android:key="bundle_array_bundle_int_key"
+                         android:restrictionType="integer"/>
+        </restriction>
+    </restriction>
+</restrictions>
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/RestrictionsManagerTest.java b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
new file mode 100644
index 0000000..8921924
--- /dev/null
+++ b/core/tests/coretests/src/android/content/RestrictionsManagerTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package android.content;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.test.AndroidTestCase;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class RestrictionsManagerTest extends AndroidTestCase {
+    private RestrictionsManager mRm;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mRm = (RestrictionsManager) mContext.getSystemService(Context.RESTRICTIONS_SERVICE);
+    }
+
+    public void testGetManifestRestrictions() {
+        String packageName = getContext().getPackageName();
+        List<RestrictionEntry> manifestRestrictions = mRm.getManifestRestrictions(packageName);
+        assertEquals(6, manifestRestrictions.size());
+        Set<String> verifiedKeys = new HashSet<>(Arrays.asList("bundle_key", "bundle_array_key",
+                "bundle_array_bundle_key"));
+        for (RestrictionEntry entry : manifestRestrictions) {
+            if ("bundle_key".equals(entry.getKey())) {
+                assertEquals("bundle_key entry should have 2 children entries",
+                        2, entry.getRestrictions().length);
+                verifiedKeys.remove(entry.getKey());
+            } else if ("bundle_array_key".equals(entry.getKey())) {
+                assertEquals("bundle_array_key should have 2 children entries",
+                        2, entry.getRestrictions().length);
+                assertNotNull(entry.getRestrictions());
+                for (RestrictionEntry childEntry : entry.getRestrictions()) {
+                    if ("bundle_array_bundle_key".equals(childEntry.getKey())) {
+                        assertNotNull(childEntry.getRestrictions());
+                        assertEquals("bundle_array_bundle_key should have 1 child entry",
+                                1, childEntry.getRestrictions().length);
+                        verifiedKeys.remove(childEntry.getKey());
+                    }
+                }
+                verifiedKeys.remove(entry.getKey());
+            }
+        }
+        assertTrue("Entries" + verifiedKeys + " were not found", verifiedKeys.isEmpty());
+    }
+
+    public void testConvertRestrictionsToBundle() {
+        String packageName = getContext().getPackageName();
+        List<RestrictionEntry> manifestRestrictions = mRm.getManifestRestrictions(packageName);
+        Bundle bundle = RestrictionsManager.convertRestrictionsToBundle(manifestRestrictions);
+        assertEquals(6, bundle.size());
+        Bundle childBundle = bundle.getBundle("bundle_key");
+        assertNotNull(childBundle);
+        assertEquals(2, childBundle.size());
+        Parcelable[] childBundleArray = bundle.getParcelableArray("bundle_array_key");
+        assertEquals(2, childBundleArray.length);
+    }
+
+}
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index cd45017..6fa28b1 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -804,4 +804,56 @@
         assertFalse(Uri.parse("content://com.example/path/path").isPathPrefixMatch(
                 Uri.parse("content://com.example/path%2Fpath")));
     }
+
+    public void testToSafeString() {
+        checkToSafeString("tel:xxxxxx", "tel:Google");
+        checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");
+        checkToSafeString("tEl:xxx.xxx-xxxx", "tEl:123.456-7890");
+
+        checkToSafeString("sms:xxxxxx", "sms:123abc");
+        checkToSafeString("smS:xxx.xxx-xxxx", "smS:123.456-7890");
+
+        checkToSafeString("smsto:xxxxxx", "smsto:123abc");
+        checkToSafeString("SMSTo:xxx.xxx-xxxx", "SMSTo:123.456-7890");
+
+        checkToSafeString("mailto:xxxxxxx@xxxxxxx.xxx", "mailto:android@android.com");
+        checkToSafeString("Mailto:xxxxxxx@xxxxxxx.xxxxxxxxxx",
+                "Mailto:android@android.com/secret");
+
+        checkToSafeString("sip:xxxxxxx@xxxxxxx.xxxxxxxx", "sip:android@android.com:1234");
+        checkToSafeString("sIp:xxxxxxx@xxxxxxx.xxx", "sIp:android@android.com");
+
+        checkToSafeString("http://www.android.com/...", "http://www.android.com");
+        checkToSafeString("HTTP://www.android.com/...", "HTTP://www.android.com");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...",
+                "http://user:pwd@www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...",
+                "http://user@www.android.com/secretUrl?param");
+        checkToSafeString("http://www.android.com/...", "http://www.android.com/secretUrl?param");
+        checkToSafeString("http:///...", "http:///path?param");
+        checkToSafeString("http:///...", "http://");
+        checkToSafeString("http://:12345/...", "http://:12345/");
+
+        checkToSafeString("https://www.android.com/...", "https://www.android.com/secretUrl?param");
+        checkToSafeString("https://www.android.com:8443/...",
+                "https://user:pwd@www.android.com:8443/secretUrl?param");
+        checkToSafeString("https://www.android.com/...", "https://user:pwd@www.android.com");
+        checkToSafeString("Https://www.android.com/...", "Https://user:pwd@www.android.com");
+
+        checkToSafeString("ftp://ftp.android.com/...", "ftp://ftp.android.com/");
+        checkToSafeString("ftP://ftp.android.com/...", "ftP://anonymous@ftp.android.com/");
+        checkToSafeString("ftp://ftp.android.com:2121/...",
+                "ftp://root:love@ftp.android.com:2121/");
+
+        checkToSafeString("unsupported://ajkakjah/askdha/secret?secret",
+                "unsupported://ajkakjah/askdha/secret?secret");
+        checkToSafeString("unsupported:ajkakjah/askdha/secret?secret",
+                "unsupported:ajkakjah/askdha/secret?secret");
+    }
+
+    private void checkToSafeString(String expectedSafeString, String original) {
+        assertEquals(expectedSafeString, Uri.parse(original).toSafeString());
+    }
 }
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 42b5d5d..5c3b90b 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -181,6 +181,18 @@
     </family>
     <family>
         <fileset>
+            <file variant="elegant">NotoSansOriya-Regular.ttf</file>
+            <file variant="elegant">NotoSansOriya-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file variant="compact">NotoSansOriyaUI-Regular.ttf</file>
+            <file variant="compact">NotoSansOriyaUI-Bold.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansSinhala-Regular.ttf</file>
             <file>NotoSansSinhala-Bold.ttf</file>
         </fileset>
@@ -355,11 +367,6 @@
     </family>
     <family>
         <fileset>
-            <file>Lohit-Odia.ttf</file>
-        </fileset>
-    </family>
-    <family>
-        <fileset>
             <file lang="zh-Hans">NotoSansHans-Regular.otf</file>
         </fileset>
     </family>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 37527e9..f3a7647 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -191,6 +191,14 @@
         <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
     </family>
+    <family variant="elegant">
+        <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font>
+    </family>
+    <family variant="compact">
+        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
+    </family>
     <family>
         <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
         <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
@@ -299,9 +307,6 @@
     <family>
         <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
-    <family>
-        <font weight="400" style="normal">Lohit-Odia.ttf</font>
-    </family>
     <family lang="zh-Hans">
         <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
     </family>
diff --git a/docs/html/about/dashboards/index.jd b/docs/html/about/dashboards/index.jd
index cfb65a5..52f086e 100644
--- a/docs/html/about/dashboards/index.jd
+++ b/docs/html/about/dashboards/index.jd
@@ -57,7 +57,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 2, 2015.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 6, 2015.
 <br/>Any versions with less than 0.1% distribution are not shown.</em>
 </p>
 
@@ -88,7 +88,7 @@
 </div>
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 2, 2015.
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 6, 2015.
 
 <br/>Any screen configurations with less than 0.1% distribution are not shown.</em></p>
 
@@ -108,8 +108,7 @@
 
 
 <img alt="" style="float:right"
-src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0&chf=bg%2Cs%2C00000000&chd=t%3A67.5%2C32.5&chco=c4df9b%2C6fad0c&cht=p&chs=400x250" />
-
+src="//chart.googleapis.com/chart?chl=GL%202.0%7CGL%203.0%7CGL%203.1&chf=bg%2Cs%2C00000000&chd=t%3A65.9%2C33.8%2C0.3&chco=c4df9b%2C6fad0c&cht=p&chs=400x250">
 
 <p>To declare which version of OpenGL ES your application requires, you should use the {@code
 android:glEsVersion} attribute of the <a
@@ -127,17 +126,21 @@
 </tr>
 <tr>
 <td>2.0</td>
-<td>67.5%</td>
+<td>65.9%</td>
 </tr>
 <tr>
 <td>3.0</td>
-<td>32.5%</td>
+<td>33.8%</td>
+</tr>
+<tr>
+<td>3.1</td>
+<td>0.3%</td>
 </tr>
 </table>
 
 
 
-<p style="clear:both"><em>Data collected during a 7-day period ending on March 2, 2015</em></p>
+<p style="clear:both"><em>Data collected during a 7-day period ending on April 6, 2015</em></p>
 
 
 
@@ -155,7 +158,7 @@
 var VERSION_DATA =
 [
   {
-    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop&chco=c4df9b%2C6fad0c&chd=t%3A0.4%2C6.9%2C5.9%2C42.6%2C40.9%2C3.3&chf=bg%2Cs%2C00000000&chs=500x250&cht=p",
+    "chart": "//chart.googleapis.com/chart?chl=Froyo%7CGingerbread%7CIce%20Cream%20Sandwich%7CJelly%20Bean%7CKitKat%7CLollipop&chf=bg%2Cs%2C00000000&chd=t%3A0.4%2C6.4%2C5.7%2C40.7%2C41.4%2C5.4&chco=c4df9b%2C6fad0c&chs=500x250&cht=p",
     "data": [
       {
         "api": 8,
@@ -165,37 +168,42 @@
       {
         "api": 10,
         "name": "Gingerbread",
-        "perc": "6.9"
+        "perc": "6.4"
       },
       {
         "api": 15,
         "name": "Ice Cream Sandwich",
-        "perc": "5.9"
+        "perc": "5.7"
       },
       {
         "api": 16,
         "name": "Jelly Bean",
-        "perc": "17.3"
+        "perc": "16.5"
       },
       {
         "api": 17,
         "name": "Jelly Bean",
-        "perc": "19.4"
+        "perc": "18.6"
       },
       {
         "api": 18,
         "name": "Jelly Bean",
-        "perc": "5.9"
+        "perc": "5.6"
       },
       {
         "api": 19,
         "name": "KitKat",
-        "perc": "40.9"
+        "perc": "41.4"
       },
       {
         "api": 21,
         "name": "Lollipop",
-        "perc": "3.3"
+        "perc": "5.0"
+      },
+      {
+        "api": 22,
+        "name": "Lollipop",
+        "perc": "0.4"
       }
     ]
   }
@@ -208,29 +216,29 @@
     "data": {
       "Large": {
         "hdpi": "0.6",
-        "ldpi": "0.5",
-        "mdpi": "5.1",
-        "tvdpi": "2.3",
+        "ldpi": "0.4",
+        "mdpi": "4.8",
+        "tvdpi": "2.2",
         "xhdpi": "0.6"
       },
       "Normal": {
-        "hdpi": "38.7",
-        "mdpi": "8.4",
+        "hdpi": "39.3",
+        "mdpi": "8.1",
         "tvdpi": "0.1",
-        "xhdpi": "18.9",
-        "xxhdpi": "15.8"
+        "xhdpi": "19.5",
+        "xxhdpi": "15.9"
       },
       "Small": {
-        "ldpi": "4.6"
+        "ldpi": "4.4"
       },
       "Xlarge": {
         "hdpi": "0.3",
-        "mdpi": "3.5",
+        "mdpi": "3.2",
         "xhdpi": "0.6"
       }
     },
-    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chco=c4df9b%2C6fad0c&chd=t%3A5.1%2C17.0%2C2.4%2C39.6%2C20.1%2C15.8&chf=bg%2Cs%2C00000000&chs=400x250&cht=p",
-    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chco=c4df9b%2C6fad0c&chd=t%3A4.4%2C9.1%2C81.9%2C4.6&chf=bg%2Cs%2C00000000&chs=400x250&cht=p"
+    "densitychart": "//chart.googleapis.com/chart?chl=ldpi%7Cmdpi%7Ctvdpi%7Chdpi%7Cxhdpi%7Cxxhdpi&chf=bg%2Cs%2C00000000&chd=t%3A4.8%2C16.1%2C2.3%2C40.2%2C20.7%2C15.9&chco=c4df9b%2C6fad0c&chs=400x250&cht=p",
+    "layoutchart": "//chart.googleapis.com/chart?chl=Xlarge%7CLarge%7CNormal%7CSmall&chf=bg%2Cs%2C00000000&chd=t%3A4.1%2C8.6%2C82.9%2C4.4&chco=c4df9b%2C6fad0c&chs=400x250&cht=p"
   }
 ];
 
@@ -312,6 +320,11 @@
     "api":21,
     "link":"<a href='/about/versions/android-5.0.html'>5.0</a>",
     "codename":"Lollipop"
+  },
+  {
+    "api":22,
+    "link":"<a href='/about/versions/android-5.1.html'>5.1</a>",
+    "codename":"Lollipop"
   }
 ];
 
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index 6ae7c1a..bc58e66 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -33,7 +33,10 @@
 </div>
 </div>
 
-<p>Android Cloud to Device Messaging (C2DM) is deprecated. The C2DM service will continue to be maintained in the short term, but C2DM will accept no new users, and it will grant no new quotas. <strong>C2DM developers are strongly encouraged to move to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+<p>Android Cloud to Device Messaging (C2DM) was officially deprecated on June 26, 2012, and will be
+ shut down completely as of July 30, 2015.  <strong>C2DM developers are strongly encouraged to move
+  to Google Cloud Messaging (GCM)</strong>. GCM is the next generation of C2DM.</p>
+
 <p>This document is addressed to  C2DM developers who are moving to GCM. It describes the differences between GCM and C2DM, and explains how to migrate existing C2DM apps to GCM.</p>
 
 
diff --git a/docs/html/google/play-services/setup.jd b/docs/html/google/play-services/setup.jd
index 3f71d04..70e7107 100644
--- a/docs/html/google/play-services/setup.jd
+++ b/docs/html/google/play-services/setup.jd
@@ -9,7 +9,7 @@
 <h2>In this document</h2>
 <ol>
   <li><a href="#Setup">Add Google Play Services to Your Project</a></li>
-  <li><a href="#Proguard">Create a Proguard Exception</a></li>
+  <li><a href="#Proguard">Create a ProGuard Exception</a></li>
   <li><a href="#ensure">Ensure Devices Have the Google Play services APK</a></li>
 </ol>
 
@@ -82,14 +82,6 @@
 <img src="{@docRoot}images/tools/sync-project.png" style="vertical-align:bottom;margin:0;height:19px" />
 in the toolbar.
   </li>
-  <li>Open your app's manifest file and add the following tag as a child of the <a
-href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application>}</a>
-element:
-<pre>
-&lt;meta-data android:name="com.google.android.gms.version"
-           android:value="&#64;integer/google_play_services_version" />
-</pre>
-  </li>
 </ol>
 
 <p>You can now begin developing features with the
@@ -203,6 +195,17 @@
   </tr>
 </table>
 
+<p class="note"><strong>Note:</strong> ProGuard directives are included in the Play services
+client libraries to preserve the required classes. The
+<a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plugin for Gradle</a>
+automatically appends ProGuard configuration files in an AAR (Android ARchive) package and appends
+that package to your ProGuard configuration. During project creation, Android Studio automatically
+creates the ProGuard configuration files and <code>build.gradle</code> properties for ProGuard use.
+To use ProGuard with Android Studio, you must enable the ProGuard setting in your
+<code>build.gradle</code>  <code>buildTypes</code>. For more information, see the
+<a href="{@docRoot}tools/help/proguard.html">ProGuard</a> topic. </p>
+
+
 </div><!-- end studio -->
 
 <div class="select-ide eclipse">
@@ -238,6 +241,33 @@
 you can begin developing features with the
 <a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
 
+
+<h2 id="Proguard">Create a ProGuard Exception</h2>
+
+<p>To prevent <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> from stripping away
+required classes, add the following lines in the
+<code>&lt;project_directory&gt;/proguard-project.txt</code> file:
+<pre>
+-keep class * extends java.util.ListResourceBundle {
+    protected Object[][] getContents();
+}
+
+-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
+    public static final *** NULL;
+}
+
+-keepnames &#64;com.google.android.gms.common.annotation.KeepName class *
+-keepclassmembernames class * {
+    &#64;com.google.android.gms.common.annotation.KeepName *;
+}
+
+-keepnames class * implements android.os.Parcelable {
+    public static final ** CREATOR;
+}
+</pre>
+
+
+
 </div><!-- end eclipse -->
 
 <div class="select-ide other">
@@ -271,8 +301,6 @@
 you can begin developing features with the
 <a href="{@docRoot}reference/gms-packages.html">Google Play services APIs</a>.</p>
 
-</div><!-- end other -->
-
 
 <h2 id="Proguard">Create a Proguard Exception</h2>
 
@@ -298,11 +326,9 @@
 }
 </pre>
 
-<p class="note"><strong>Note:</strong> When using Android Studio, you must add Proguard
-to your <code>build.gradle</code> file's build types. For more information, see the
-<a href="http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard"
->Gradle Plugin User Guide</a>.
-</ol>
+
+</div><!-- end other -->
+
 
 
 <h2 id="ensure">Ensure Devices Have the Google Play services APK</h2>
diff --git a/docs/html/google/play/billing/billing_integrate.jd b/docs/html/google/play/billing/billing_integrate.jd
index e3cacf9..eb58af4 100644
--- a/docs/html/google/play/billing/billing_integrate.jd
+++ b/docs/html/google/play/billing/billing_integrate.jd
@@ -34,7 +34,7 @@
   <h2>See also</h2>
   <ol>
     <li><a href="{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a></li>
-  </ol>  
+  </ol>
 </div>
 </div>
 
@@ -42,26 +42,26 @@
 
 <p class="note"><strong>Note:</strong> To see a complete implementation and learn how to test your application, see the <a href="{@docRoot}training/in-app-billing/index.html">Selling In-app Products</a> training class. The training class provides a complete sample In-app Billing application, including convenience classes to handle key tasks related to setting up your connection, sending billing requests and processing responses from Google Play, and managing background threading so that you can make In-app Billing calls from your main activity.</p>
 
-<p>Before you start, be sure that you read the <a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing Overview</a> to familiarize yourself with 
+<p>Before you start, be sure that you read the <a href="{@docRoot}google/play/billing/billing_overview.html">In-app Billing Overview</a> to familiarize yourself with
 concepts that will make it easier for you to implement In-app Billing.</p>
 
-<p>To implement In-app Billing in your application, you need to do the 
+<p>To implement In-app Billing in your application, you need to do the
 following:</p>
 <ol>
   <li>Add the In-app Billing library to your project.</li>
   <li>Update your {@code AndroidManifest.xml} file.</li>
-  <li>Create a {@code ServiceConnection} and bind it to 
+  <li>Create a {@code ServiceConnection} and bind it to
 {@code IInAppBillingService}.</li>
-  <li>Send In-app Billing requests from your application to 
+  <li>Send In-app Billing requests from your application to
 {@code IInAppBillingService}.</li>
   <li>Handle In-app Billing responses from Google Play.</li>
 </ol>
 
 <h2 id="billing-add-aidl">Adding the AIDL file to your project</h2>
 
-<p>{@code IInAppBillingService.aidl} is an Android Interface Definition 
-Language (AIDL) file that defines the interface to the In-app Billing Version 
-3 service. You will use this interface to make billing requests by invoking IPC 
+<p>{@code IInAppBillingService.aidl} is an Android Interface Definition
+Language (AIDL) file that defines the interface to the In-app Billing Version
+3 service. You will use this interface to make billing requests by invoking IPC
 method calls.</p>
 <p>To get the AIDL file:</p>
 <ol>
@@ -76,28 +76,28 @@
 <ol>
 <li>Copy the {@code IInAppBillingService.aidl} file to your Android project.
   <ul>
-  <li>If you are using Eclipse: 
+  <li>If you are using Eclipse:
      <ol type="a">
-        <li>If you are starting from an existing Android project, open the project 
-in Eclipse. If you are creating a new Android project from scratch, click 
-<strong>File</strong> &gt; <strong>New</strong> &gt; <strong>Android Application 
-Project</strong>, then follow the instructions in the <strong>New Android 
+        <li>If you are starting from an existing Android project, open the project
+in Eclipse. If you are creating a new Android project from scratch, click
+<strong>File</strong> &gt; <strong>New</strong> &gt; <strong>Android Application
+Project</strong>, then follow the instructions in the <strong>New Android
 Application</strong> wizard to create a new project in your workspace.</li>
-	<li>In the {@code /src} directory, click <strong>File</strong> &gt; 
+	<li>In the {@code /src} directory, click <strong>File</strong> &gt;
 <strong>New</strong> &gt; <strong>Package</strong>, then create a package named {@code com.android.vending.billing}.</li>
-	<li>Copy the {@code IInAppBillingService.aidl} file from {@code &lt;sdk&gt;/extras/google/play_billing/} and paste it into the {@code src/com.android.vending.billing/} 
+	<li>Copy the {@code IInAppBillingService.aidl} file from {@code &lt;sdk&gt;/extras/google/play_billing/} and paste it into the {@code src/com.android.vending.billing/}
 folder in your workspace.</li>
      </ol>
   </li>
-  <li>If you are developing in a non-Eclipse environment: Create the following 
-directory {@code /src/com/android/vending/billing} and copy the 
-{@code IInAppBillingService.aidl} file into this directory. Put the AIDL file 
+  <li>If you are developing in a non-Eclipse environment: Create the following
+directory {@code /src/com/android/vending/billing} and copy the
+{@code IInAppBillingService.aidl} file into this directory. Put the AIDL file
 into your project and use the Ant tool to build your project so that the
 <code>IInAppBillingService.java</code> file gets generated.</li>
   </ul>
 </li>
-<li>Build your application. You should see a generated file named 
-{@code IInAppBillingService.java} in the {@code /gen} directory of your 
+<li>Build your application. You should see a generated file named
+{@code IInAppBillingService.java} in the {@code /gen} directory of your
 project.</li>
 </ol>
 
@@ -135,7 +135,7 @@
    }
 
    &#64;Override
-   public void onServiceConnected(ComponentName name, 
+   public void onServiceConnected(ComponentName name,
       IBinder service) {
        mService = IInAppBillingService.Stub.asInterface(service);
    }
@@ -162,7 +162,7 @@
     super.onDestroy();
     if (mService != null) {
         unbindService(mServiceConn);
-    }	
+    }
 }
 </pre>
 
@@ -185,13 +185,13 @@
 </pre>
 <p>To retrieve this information from Google Play, call the {@code getSkuDetails} method on the In-app Billing Version 3 API, and pass the method the In-app Billing API version (“3”), the package name of your calling app, the purchase type (“inapp”), and the {@link android.os.Bundle} that you created.</p>
 <pre>
-Bundle skuDetails = mService.getSkuDetails(3, 
+Bundle skuDetails = mService.getSkuDetails(3,
    getPackageName(), "inapp", querySkus);
 </pre>
 <p>If the request is successful, the returned {@link android.os.Bundle}has a response code of {@code BILLING_RESPONSE_RESULT_OK} (0).</p>
 <p class="note"><strong>Warning:</strong> Do not call the {@code getSkuDetails} method on the main thread. Calling this method triggers a network request which could block your main thread.  Instead, create a separate thread and call the {@code getSkuDetails} method from inside that thread.</p>
 
-<p>To see all the possible response codes from Google Play, see <a href="{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app Billing Reference</a>.</p>  
+<p>To see all the possible response codes from Google Play, see <a href="{@docRoot}google/play/billing/billing_reference.html#billing-codes">In-app Billing Reference</a>.</p>
 
 <p>The query results are stored in a String ArrayList with key {@code DETAILS_LIST}.  The purchase information is stored in the String in JSON format. To see the types of product detail information that are returned, see <a href="{@docRoot}google/play/billing/billing_reference.html#getSkuDetails">In-app Billing Reference</a>.</p>
 
@@ -201,7 +201,7 @@
 if (response == 0) {
    ArrayList&lt;String&gt; responseList
       = skuDetails.getStringArrayList("DETAILS_LIST");
-   
+
    for (String thisResponse : responseList) {
       JSONObject object = new JSONObject(thisResponse);
       String sku = object.getString("productId");
@@ -232,12 +232,12 @@
    1001, new Intent(), Integer.valueOf(0), Integer.valueOf(0),
    Integer.valueOf(0));
 </pre>
-<p>Google Play sends a response to your {@link android.app.PendingIntent} to the {@link android.app.Activity#onActivityResult onActivityResult} method of your application. The {@link android.app.Activity#onActivityResult onActivityResult} method will have a result code of {@code Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To see the types of order information that is returned in the response {@link android.content.Intent}, see <a href="{@docRoot}google/play/billing/billing_reference.html#getBuyIntent">In-app Billing Reference</a>.</p> 
+<p>Google Play sends a response to your {@link android.app.PendingIntent} to the {@link android.app.Activity#onActivityResult onActivityResult} method of your application. The {@link android.app.Activity#onActivityResult onActivityResult} method will have a result code of {@code Activity.RESULT_OK} (1) or {@code Activity.RESULT_CANCELED} (0). To see the types of order information that is returned in the response {@link android.content.Intent}, see <a href="{@docRoot}google/play/billing/billing_reference.html#getBuyIntent">In-app Billing Reference</a>.</p>
 
 <p>The purchase data for the order is a String in JSON format that is mapped to the {@code INAPP_PURCHASE_DATA} key in the response {@link android.content.Intent}, for example:
 <pre>
-'{ 
-   "orderId":"12999763169054705758.1371079406387615", 
+'{
+   "orderId":"12999763169054705758.1371079406387615",
    "packageName":"com.example.app",
    "productId":"exampleSku",
    "purchaseTime":1345678900000,
@@ -259,17 +259,17 @@
 <p>Continuing from the previous example, you get the response code, purchase data, and signature from the response {@link android.content.Intent}.</p>
 <pre>
 &#64;Override
-protected void onActivityResult(int requestCode, int resultCode, Intent data) {	
-   if (requestCode == 1001) {    	
+protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+   if (requestCode == 1001) {
       int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
       String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
       String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
-        
+
       if (resultCode == RESULT_OK) {
          try {
             JSONObject jo = new JSONObject(purchaseData);
             String sku = jo.getString("productId");
-            alert("You have bought the " + sku + ". Excellent choice, 
+            alert("You have bought the " + sku + ". Excellent choice,
                adventurer!");
           }
           catch (JSONException e) {
@@ -298,45 +298,45 @@
    ArrayList&lt;String&gt;  purchaseDataList =
       ownedItems.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
    ArrayList&lt;String&gt;  signatureList =
-      ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE");
-   String continuationToken = 
+      ownedItems.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
+   String continuationToken =
       ownedItems.getString("INAPP_CONTINUATION_TOKEN");
-   
+
    for (int i = 0; i < purchaseDataList.size(); ++i) {
       String purchaseData = purchaseDataList.get(i);
       String signature = signatureList.get(i);
       String sku = ownedSkus.get(i);
-  
+
       // do something with this purchase information
       // e.g. display the updated list of products owned by user
-   } 
+   }
 
-   // if continuationToken != null, call getPurchases again 
+   // if continuationToken != null, call getPurchases again
    // and pass in the token to retrieve more items
 }
 
 </pre>
 
 <h3 id="Consume">Consuming a Purchase</h3>
-<p>You can use the In-app Billing Version 3 API to track the ownership of 
-purchased in-app products in Google Play. Once an in-app product is purchased, 
-it is considered to be "owned" and cannot be purchased from Google Play. You 
-must send a consumption request for the in-app product before Google Play makes 
+<p>You can use the In-app Billing Version 3 API to track the ownership of
+purchased in-app products in Google Play. Once an in-app product is purchased,
+it is considered to be "owned" and cannot be purchased from Google Play. You
+must send a consumption request for the in-app product before Google Play makes
 it available for purchase again.</p>
-<p class="caution"><strong>Important</strong>: Managed in-app products are 
+<p class="caution"><strong>Important</strong>: Managed in-app products are
 consumable, but subscriptions are not.</p>
-<p>How you use the consumption mechanism in your app is up to you. Typically, 
-you would implement consumption for in-app products with temporary benefits that 
-users may want to purchase multiple times (for example, in-game currency or 
-equipment). You would typically not want to implement consumption for in-app 
-products that are purchased once and provide a permanent effect (for example, 
+<p>How you use the consumption mechanism in your app is up to you. Typically,
+you would implement consumption for in-app products with temporary benefits that
+users may want to purchase multiple times (for example, in-game currency or
+equipment). You would typically not want to implement consumption for in-app
+products that are purchased once and provide a permanent effect (for example,
 a premium upgrade).</p>
-<p>To record a purchase consumption, send the {@code consumePurchase} method to 
-the In-app Billing service and pass in the {@code purchaseToken} String value 
-that identifies the purchase to be removed. The {@code purchaseToken} is part 
-of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google 
-Play service following a successful purchase request. In this example, you are 
-recording the consumption of a product that is identified with the 
+<p>To record a purchase consumption, send the {@code consumePurchase} method to
+the In-app Billing service and pass in the {@code purchaseToken} String value
+that identifies the purchase to be removed. The {@code purchaseToken} is part
+of the data returned in the {@code INAPP_PURCHASE_DATA} String by the Google
+Play service following a successful purchase request. In this example, you are
+recording the consumption of a product that is identified with the
 {@code purchaseToken} in the {@code token} variable.</p>
 <pre>
 int response = mService.consumePurchase(3, getPackageName(), token);
@@ -346,10 +346,10 @@
 <p class="note"><strong>Security Recommendation:</strong> You must send a consumption request before provisioning the benefit of the consumable in-app purchase to the user. Make sure that you have received a successful consumption response from Google Play before you provision the item.</p>
 
 <h3 id="Subs">Implementing Subscriptions</h3>
-<p>Launching a purchase flow for a subscription is similar to launching the 
-purchase flow for a product, with the exception that the product type must be set 
-to "subs". The purchase result is delivered to your Activity's 
-{@link android.app.Activity#onActivityResult onActivityResult} method, exactly 
+<p>Launching a purchase flow for a subscription is similar to launching the
+purchase flow for a product, with the exception that the product type must be set
+to "subs". The purchase result is delivered to your Activity's
+{@link android.app.Activity#onActivityResult onActivityResult} method, exactly
 as in the case of in-app products.</p>
 <pre>
 Bundle bundle = mService.getBuyIntent(3, "com.example.myapp",
@@ -363,39 +363,39 @@
        Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0));
 }
 </pre>
-<p>To query for active subscriptions, use the {@code getPurchases} method, again 
+<p>To query for active subscriptions, use the {@code getPurchases} method, again
 with the product type parameter set to "subs".</p>
 <pre>
 Bundle activeSubs = mService.getPurchases(3, "com.example.myapp",
                    "subs", continueToken);
 </pre>
-<p>The call returns a {@code Bundle} with all the active subscriptions owned by 
-the user. Once a subscription expires without renewal, it will no longer appear 
+<p>The call returns a {@code Bundle} with all the active subscriptions owned by
+the user. Once a subscription expires without renewal, it will no longer appear
 in the returned {@code Bundle}.</p>
 
 <h2 id="billing-security">Securing Your Application</h2>
 
-<p>To help ensure the integrity of the transaction information that is sent to 
-your application, Google Play signs the JSON string that contains the response 
-data for a purchase order. Google Play uses the private key that is associated 
-with your application in the Developer Console to create this signature. The 
+<p>To help ensure the integrity of the transaction information that is sent to
+your application, Google Play signs the JSON string that contains the response
+data for a purchase order. Google Play uses the private key that is associated
+with your application in the Developer Console to create this signature. The
 Developer Console generates an RSA key pair for each application.<p>
 
-<p class="note"><strong>Note:</strong>To find the public key portion of this key 
-pair, open your application's details in the Developer Console, then click on 
-<strong>Services & APIs</strong>, and look at the field titled 
+<p class="note"><strong>Note:</strong>To find the public key portion of this key
+pair, open your application's details in the Developer Console, then click on
+<strong>Services & APIs</strong>, and look at the field titled
 <strong>Your License Key for This Application</strong>.</p>
 
-<p>The Base64-encoded RSA public key generated by Google Play is in binary 
-encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public 
+<p>The Base64-encoded RSA public key generated by Google Play is in binary
+encoded, X.509 subjectPublicKeyInfo DER SEQUENCE format. It is the same public
 key that is used with Google Play licensing.</p>
 
-<p>When your application receives this signed response you can 
-use the public key portion of your RSA key pair to verify the signature. 
-By performing signature verification you can detect responses that have 
-been tampered with or that have been spoofed. You can perform this signature 
-verification step in your application; however, if your application connects 
-to a secure remote server then we recommend that you perform the signature 
+<p>When your application receives this signed response you can
+use the public key portion of your RSA key pair to verify the signature.
+By performing signature verification you can detect responses that have
+been tampered with or that have been spoofed. You can perform this signature
+verification step in your application; however, if your application connects
+to a secure remote server then we recommend that you perform the signature
 verification on that server.</p>
 
 <p>For more information about best practices for security and design, see <a
diff --git a/docs/html/guide/index.jd b/docs/html/guide/index.jd
index d78a1b1..cb4f65c 100644
--- a/docs/html/guide/index.jd
+++ b/docs/html/guide/index.jd
@@ -30,7 +30,7 @@
 work in the background.</p>
 
 <p>From one component you can start another component using an <em>intent</em>. You can even start
-a component in a different app, such an activity in a maps app to show an address. This model
+a component in a different app, such as an activity in a maps app to show an address. This model
 provides multiple entry points for a single app and allows any app to behave as a user's "default"
 for an action that other apps may invoke.</p>
 
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index c1256f9..99e64d9 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -13,10 +13,11 @@
           android:<a href="#clear">clearTaskOnLaunch</a>=["true" | "false"]
           android:<a href="#config">configChanges</a>=["mcc", "mnc", "locale",
                                  "touchscreen", "keyboard", "keyboardHidden",
-                                 "navigation", "screenLayout", "fontScale", "uiMode",
-                                 "orientation", "screenSize", "smallestScreenSize"]
-          android:<a href="#dlmode">documentLaunchMode</a>=["intoExisting", "always",
-                                  "none", "never"]
+                                 "navigation", "screenLayout", "fontScale",
+                                 "uiMode", "orientation", "screenSize",
+                                 "smallestScreenSize"]
+          android:<a href="#dlmode">documentLaunchMode</a>=["intoExisting" | "always" |
+                                  "none" | "never"]
           android:<a href="#enabled">enabled</a>=["true" | "false"]
           android:<a href="#exclude">excludeFromRecents</a>=["true" | "false"]
           android:<a href="#exported">exported</a>=["true" | "false"]
diff --git a/docs/html/images/tv/channel-info.png b/docs/html/images/tv/channel-info.png
new file mode 100644
index 0000000..5a48078
--- /dev/null
+++ b/docs/html/images/tv/channel-info.png
Binary files differ
diff --git a/docs/html/images/tv/do-not-attempt.png b/docs/html/images/tv/do-not-attempt.png
new file mode 100644
index 0000000..18a8775
--- /dev/null
+++ b/docs/html/images/tv/do-not-attempt.png
Binary files differ
diff --git a/docs/html/images/tv/prog-guide.png b/docs/html/images/tv/prog-guide.png
new file mode 100644
index 0000000..caa2278
--- /dev/null
+++ b/docs/html/images/tv/prog-guide.png
Binary files differ
diff --git a/docs/html/images/tv/tvinput-life.png b/docs/html/images/tv/tvinput-life.png
new file mode 100644
index 0000000..fc53f89
--- /dev/null
+++ b/docs/html/images/tv/tvinput-life.png
Binary files differ
diff --git a/docs/html/tools/testing-support-library/index.jd b/docs/html/tools/testing-support-library/index.jd
index aeace8e..c8c9ef5 100644
--- a/docs/html/tools/testing-support-library/index.jd
+++ b/docs/html/tools/testing-support-library/index.jd
@@ -391,7 +391,9 @@
 
   <p>
     To learn more about using Espresso, see the
-    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a>.
+    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a> and
+    <a href="{@docRoot}training/testing/ui-testing/espresso-testing.html">
+      Testing UI for a Single App</a> training.
   </p>
 
   <h3 id="UIAutomator">
@@ -531,7 +533,9 @@
 
   <p>
     To learn more about using UI Automator, see the
-    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a>.
+    <a href="{@docRoot}reference/android/support/test/package-summary.html">API reference</a> and
+    <a href="{@docRoot}training/testing/ui-testing/uiautomator-testing.html">
+      Testing UI for Multiple Apps</a> training.
   </p>
 
   <h2 id="setup">
diff --git a/docs/html/training/auto/start/index.jd b/docs/html/training/auto/start/index.jd
index 54500ac..22e7521 100644
--- a/docs/html/training/auto/start/index.jd
+++ b/docs/html/training/auto/start/index.jd
@@ -55,14 +55,6 @@
 setting up your development environment and meeting the the minimum requirements
 to enable an app to communicate with Auto.</p>
 
-<p class="note"><strong>Important:</strong> If you are planning to develop
-apps for Auto, you are encouraged to begin enabling and testing your
-apps now. However, Auto-enabled apps cannot be published at this time.
-Join the
-<a href="http://g.co/AndroidAutoDev" class="external-link">Auto
-Developers Google+ community</a> for updates on when you will be able to submit
-your Auto-enabled apps.</p>
-
 <h2 id="dev-project">Set Up an Auto Project</h2>
 <p>This section describes how to create a new app or modify an existing app to
 communicate with Auto.</p>
diff --git a/docs/html/training/custom-views/optimizing-view.jd b/docs/html/training/custom-views/optimizing-view.jd
index 7f2e762..022618b 100644
--- a/docs/html/training/custom-views/optimizing-view.jd
+++ b/docs/html/training/custom-views/optimizing-view.jd
@@ -12,33 +12,21 @@
     <div id="tb">
 
         <h2>This lesson teaches you to</h2>
-        <ol>
-            <li><a href="#less">Do Less, Less Frequently</a></li>
-            <li><a href="#accelerate">Use Hardware Acceleration</a></li>
-        </ol>
-
-        <h2>You should also read</h2>
         <ul>
-            <li><a href="{@docRoot}guide/topics/graphics/hardware-accel.html">
-                Hardware Acceleration
-            </a>
-        </li>
-    </ul>
-<h2>Try it out</h2>
-<div class="download-box">
-<a href="{@docRoot}shareables/training/CustomView.zip"
-class="button">Download the sample</a>
-<p class="filename">CustomView.zip</p>
-</div>
-</div>
+            <li><a href="#less">Do Less, Less Frequently</a></li>
+        </ul>
+        <h2>Try it out</h2>
+        <div class="download-box">
+            <a href="{@docRoot}shareables/training/CustomView.zip"
+                class="button">Download the sample</a>
+            <p class="filename">CustomView.zip</p>
         </div>
-
+    </div>
+</div>
 
 <p>Now that you have a well-designed view that responds to gestures and transitions between states,
-you need to ensure
-that the view runs fast. To avoid a UI that feels sluggish or stutters during playback, you must
-ensure that your
-animations consistently run at 60 frames per second.</p>
+ensure that the view runs fast. To avoid a UI that feels sluggish or stutters during playback,
+ensure that animations consistently run at 60 frames per second.</p>
 
 <h2 id="less">Do Less, Less Frequently</h2>
 
@@ -52,19 +40,13 @@
 allocation while an
 animation is running.</p>
 
-<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, you should also make sure
+<p>In addition to making {@link android.view.View#onDraw onDraw()} leaner, also make sure
 it's called as
 infrequently as possible. Most calls to {@link android.view.View#onDraw onDraw()} are the result of
 a call to {@link
 android.view.View#invalidate() invalidate()}, so eliminate unnecessary calls to {@link
 android.view.View#invalidate()
-invalidate()}. When possible, call the four-parameter variant of {@link
-android.view.View#invalidate() invalidate()}
-rather than the version that takes no parameters. The no-parameter variant invalidates the entire
-view, while the
-four-parameter variant invalidates only a specified portion of the view. This approach allows draw calls to
-be more efficient and
-can eliminate unnecessary invalidation of views that fall outside the invalid rectangle.</p>
+invalidate()}.</p>
 
 <p>Another very expensive operation is traversing layouts. Any time a view calls {@link
 android.view.View#requestLayout()
@@ -78,7 +60,7 @@
 as shallow as
 possible.</p>
 
-<p>If you have a complex UI, you should consider writing a custom {@link android.view.ViewGroup
+<p>If you have a complex UI, consider writing a custom {@link android.view.ViewGroup
 ViewGroup} to perform
 its layout. Unlike the built-in views, your custom view can make application-specific assumptions
 about the size and
@@ -88,89 +70,3 @@
 views, but it never
 measures them. Instead, it sets their sizes directly according to its own custom layout
 algorithm.</p>
-
-<h2 id="accelerate">Use Hardware Acceleration</h2>
-
-<p>As of Android 3.0, the Android 2D graphics system can be accelerated by the GPU (Graphics
-Processing Unit) hardware
-found in most newer Android devices. GPU hardware acceleration can result in a tremendous
-performance increase for many
-applications, but it isn't the right choice for every application. The Android framework
-gives you the ability to finely control which parts of your application are or are not
-hardware accelerated.</p>
-
-<p>See <a href="{@docRoot}guide/topics/graphics/hardware-accel.html">Hardware Acceleration</a>
-        in the Android Developers Guide for directions on how to enable acceleration at the
-        application, activity, or window level. Notice  that in addition to the directions in
-        the developer guide, you must also set your application's target API to 11 or higher by
-        specifying {@code &lt;uses-sdk
-        android:targetSdkVersion="11"/&gt;} in your {@code AndroidManifest.xml} file.</p>
-
-<p>Once you've enabled hardware acceleration, you may or may not see a performance increase.
-Mobile GPUs are very good at certain tasks, such as scaling, rotating, and translating
-bitmapped images. They are not particularly good at other tasks, such as drawing lines or curves. To
-get the most out of GPU acceleration, you should maximize the number of operations that the GPU is
-good at, and minimize the number of operations that the GPU isn't good at.</p>
-
-<p>In the PieChart example, for instance, drawing the pie is relatively expensive. Redrawing the pie
-each time it's
-rotated causes the UI to feel sluggish. The solution is to place the pie chart into a child
-{@link android.view.View} and set that
-{@link android.view.View}'s
-<a href="{@docRoot}reference/android/view/View.html#setLayerType(int, android.graphics.Paint)">
-    layer type</a> to {@link android.view.View#LAYER_TYPE_HARDWARE}, so that the GPU can cache it as
-a static
-image. The sample
-defines the child view as an inner class of {@code PieChart}, which minimizes the amount of code
-changes that are needed
-to implement this solution.</p>
-
-<pre>
-   private class PieView extends View {
-
-       public PieView(Context context) {
-           super(context);
-           if (!isInEditMode()) {
-               setLayerType(View.LAYER_TYPE_HARDWARE, null);
-           }
-       }
-       
-       &#64;Override
-       protected void onDraw(Canvas canvas) {
-           super.onDraw(canvas);
-
-           for (Item it : mData) {
-               mPiePaint.setShader(it.mShader);
-               canvas.drawArc(mBounds,
-                       360 - it.mEndAngle,
-                       it.mEndAngle - it.mStartAngle,
-                       true, mPiePaint);
-           }
-       }
-
-       &#64;Override
-       protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-           mBounds = new RectF(0, 0, w, h);
-       }
-
-       RectF mBounds;
-   }
-</pre>
-
-<p>After this code change, {@code PieChart.PieView.onDraw()} is called only when the view is first
-shown. During the rest
-of the application's lifetime, the pie chart is cached as an image, and redrawn at different
-rotation angles by the GPU.
-GPU hardware is particularly good at this sort of thing, and the performance difference is
-immediately noticeable.</p>
-
-<p>There is a tradeoff, though. Caching images as hardware layers consumes video memory, which is a
-limited resource.
-For this reason, the final version of {@code PieChart.PieView} only sets its layer type to
-{@link android.view.View#LAYER_TYPE_HARDWARE}
-while the user is actively scrolling. At all other times, it sets its layer type to
-{@link android.view.View#LAYER_TYPE_NONE}, which
-allows the GPU to stop caching the image.</p>
-
-<p>Finally, don't forget to profile your code. Techniques that improve performance on one view
-might negatively affect performance on another.</p>
diff --git a/docs/html/training/testing/ui-testing/espresso-testing.jd b/docs/html/training/testing/ui-testing/espresso-testing.jd
new file mode 100644
index 0000000..85f4ba4
--- /dev/null
+++ b/docs/html/training/testing/ui-testing/espresso-testing.jd
@@ -0,0 +1,579 @@
+page.title=Testing UI for a Single App
+page.tags=testing,espresso
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+
+        <ul>
+          <li>Android 2.2 (API level 8) or higher
+          </li>
+
+          <li>
+            <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support
+            Library</a>
+          </li>
+        </ul>
+
+        <h2>
+          This lesson teaches you to
+        </h2>
+
+        <ol>
+          <li>
+            <a href="#setup">Set Up Espresso</a>
+          </li>
+
+          <li>
+            <a href="#build">Create an Espresso Test Class</a>
+          </li>
+
+          <li>
+            <a href="#run">Run Espresso Tests on a Device or Emulator</a>
+          </li>
+        </ol>
+
+        <h2>
+          You should also read
+        </h2>
+
+        <ul>
+           <li><a href="{@docRoot}reference/android/support/test/package-summary.html">
+              Espresso API Reference</a></li>
+        </ul>
+
+        <h2>
+          Try it out
+        </h2>
+
+        <ul>
+          <li>
+            <a href="https://github.com/googlesamples/android-testing"
+            class="external-link">Espresso Code Samples</a>
+          </li>
+        </ul>
+      </div>
+    </div>
+
+    <p>
+      Testing user interactions
+      within a single app helps to ensure that users do not
+      encounter unexpected results or have a poor experience when interacting with your app.
+      You should get into the habit of creating user interface (UI) tests if you need to verify
+      that the UI of your app is functioning correctly.
+    </p>
+
+    <p>
+      The Espresso testing framework, provided by the
+      <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>,
+      provides APIs for writing UI tests to simulate user interactions within a
+      single target app. Espresso tests can run on devices running Android 2.2 (API level 8) and
+      higher. A key benefit of using Espresso is that it provides automatic synchronization of test
+      actions with the UI of the app you are testing. Espresso detects when the main thread is idle,
+      so it is able to run your test commands at the appropriate time, improving the reliability of
+      your tests. This capability also relieves you from having to adding any timing workarounds,
+      such as a sleep period, in your test code.
+    </p>
+
+    <p>
+      The Espresso testing framework is an instrumentation-based API and works
+      with the
+      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code
+      AndroidJUnitRunner}</a> test runner.
+    </p>
+
+    <h2 id="setup">
+      Set Up Espresso
+    </h2>
+
+    <p>
+      Before you begin using Espresso, you must:
+    </p>
+
+    <ul>
+      <li>
+        <strong>Install the Android Testing Support Library</strong>. The Espresso API is
+        located under the {@code com.android.support.test.espresso} package. These classes allow
+        you to create tests that use the Espresso testing framework. To learn how to install the
+        library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
+        Testing Support Library Setup</a>.
+      </li>
+
+      <li>
+        <strong>Set up your project structure.</strong> In your Gradle project, the source code for
+        the target app that you want to test is typically placed under the {@code app/src/main}
+        folder. The source code for instrumentation tests, including
+        your Espresso tests, must be placed under the <code>app/src/androidTest</code> folder. To
+        learn more about setting up your project directory, see
+        <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
+      </li>
+
+      <li>
+        <strong>Specify your Android testing dependencies</strong>. In order for the
+        <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
+        correctly build and run your Espresso tests, you must specify the following libraries in
+        the {@code build.gradle} file of your Android app module:
+
+        <pre>
+dependencies {
+    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
+}
+</pre>
+      </li>
+
+      <li>
+        <strong>Turn off animations on your test device.</strong> Leaving system animations turned
+        on in the test device might cause unexpected results or may lead your test to fail. Turn
+        off animations from <em>Settings</em> by opening <em>Developing Options</em> and
+        turning all the following options off:
+        <ul>
+          <li>
+            <em>Window animation scale</em>
+          </li>
+
+          <li>
+            <em>Transition animation scale</em>
+          </li>
+
+          <li>
+            <em>Animator duration scale</em>
+          </li>
+        </ul>
+      </li>
+    </ul>
+
+    <h2 id="build">
+      Create an Espresso Test Class
+    </h2>
+
+    <p>
+      To create an Espresso test, create a Java class or an
+      {@link android.test.ActivityInstrumentationTestCase2}
+      subclass that follows this programming model:
+    </p>
+
+    <ol>
+      <li>Find the UI component you want to test in an {@link android.app.Activity} (for example, a
+      sign-in button in the app) by calling the
+      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+        {@code onView()}</a> method, or the
+      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">
+      {@code onData()}</a> method for {@link android.widget.AdapterView} controls.
+      </li>
+
+      <li>Simulate a specific user interaction to perform on that UI component, by calling the
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
+      or
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
+      method and passing in the user action (for example, click on the sign-in button). To sequence
+      multiple actions on the same UI component, chain them using a comma-separated list in your
+      method argument.
+      </li>
+
+      <li>Repeat the steps above as necessary, to simulate a user flow across multiple
+      activities in the target app.
+      </li>
+
+      <li>Use the
+    <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
+        methods to check that the UI reflects the expected
+      state or behavior, after these user interactions are performed.
+      </li>
+    </ol>
+
+    <p>
+      These steps are covered in more detail in the sections below.
+    </p>
+
+    <p>
+      The following code snippet shows how your test class might invoke this basic workflow:
+    </p>
+
+<pre>
+onView(withId(R.id.my_view))            // withId(R.id.my_view) is a ViewMatcher
+        .perform(click())               // click() is a ViewAction
+        .check(matches(isDisplayed())); // matches(isDisplayed()) is a ViewAssertion
+</pre>
+
+    <h3 id="espresso-aitc2">
+      Using Espresso with ActivityInstrumentationTestCase2
+    </h3>
+
+    <p>
+      If you are subclassing {@link android.test.ActivityInstrumentationTestCase2}
+      to create your Espresso test class, you must inject an
+      {@link android.app.Instrumentation} instance into your test class. This step is required in
+      order for your Espresso test to run with the
+      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+      test runner.
+    </p>
+
+    <p>
+      To do this, call the
+      {@link android.test.InstrumentationTestCase#injectInstrumentation(android.app.Instrumentation) injectInstrumentation()}
+      method and pass in the result of
+      <a href="{@docRoot}reference/android/support/test/InstrumentationRegistry.html#getInstrumentation()">
+      {@code InstrumentationRegistry.getInstrumentation()}</a>, as shown in the following code
+      example:
+    </p>
+
+<pre>
+import android.support.test.InstrumentationRegistry;
+
+public class MyEspressoTest
+        extends ActivityInstrumentationTestCase2&lt;MyActivity&gt; {
+
+    private MyActivity mActivity;
+
+    public MyEspressoTest() {
+        super(MyActivity.class);
+    }
+
+    &#64;Before
+    public void setUp() throws Exception {
+        super.setUp();
+        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+        mActivity = getActivity();
+    }
+
+   ...
+}
+</pre>
+
+<p class="note"><strong>Note:</strong> Previously, {@link android.test.InstrumentationTestRunner}
+would inject the {@link android.app.Instrumentation} instance, but this test runner is being
+deprecated.</p>
+
+    <h3 id="accessing-ui-components">
+      Accessing UI Components
+    </h3>
+
+    <p>
+      Before Espresso can interact with the app under test, you must first specify the UI component
+      or <em>view</em>. Espresso supports the use of
+<a href="http://hamcrest.org/" class="external-link">Hamcrest matchers</a>
+      for specifying views and adapters in your app.
+    </p>
+
+    <p>
+      To find the view, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a>
+      method and pass in a view matcher that specifies the view that you are targeting. This is
+      described in more detail in <a href="#specifying-view-matcher">Specifying a View Matcher</a>.
+      The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a> method returns a
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html">
+      {@code ViewInteraction}</a>
+      object that allows your test to interact with the view.
+      However, calling  the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a> method may not work if you want to locate a view in
+      an {@link android.widget.AdapterView} layout. In this case, follow the instructions in
+      <a href="#locating-adpeterview-view">Locating a view in an AdapterView</a> instead.
+    </p>
+
+    <p class="note">
+      <strong>Note</strong>: The <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+      {@code onView()}</a> method does not check if the view you specified is
+      valid. Instead, Espresso searches only the current view hierarchy, using the matcher provided.
+      If no match is found, the method throws a
+      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
+      {@code NoMatchingViewException}</a>.
+    </p>
+
+    <p>
+      The following code snippet shows how you might write a test that accesses an
+      {@link android.widget.EditText} field, enters a string of text, closes the virtual keyboard,
+      and then performs a button click.
+    </p>
+
+<pre>
+public void testChangeText_sameActivity() {
+    // Type text and then press the button.
+    onView(withId(R.id.editTextUserInput))
+            .perform(typeText(STRING_TO_BE_TYPED), closeSoftKeyboard());
+    onView(withId(R.id.changeTextButton)).perform(click());
+
+    // Check that the text was changed.
+    ...
+}
+</pre>
+
+    <h4 id="specifying-view-matcher">
+      Specifying a View Matcher
+    </h4>
+
+    <p>
+      You can specify a view matcher by using these approaches:
+    </p>
+
+    <ul>
+      <li>Calling methods in the
+        <a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html">
+        {@code ViewMatchers}</a> class. For example, to find a view by looking for a text string it
+        displays, you can call a method like this:
+        <pre>
+onView(withText("Sign-in"));
+</pre>
+
+<p>Similarly you can call
+<a href="{@docRoot}reference/android/support/test/espresso/matcher/ViewMatchers.html#withId(int)">
+{@code withId()}</a> and providing the resource ID ({@code R.id}) of the view, as shown in the
+following example:</p>
+
+<pre>
+onView(withId(R.id.button_signin));
+</pre>
+
+    <p>
+      Android resource IDs are not guaranteed to be unique. If your test attempts to match to a
+      resource ID used by more than one view, Espresso throws an
+<a href="{@docRoot}reference/android/support/test/espresso/AmbiguousViewMatcherException.html">
+  {@code AmbiguousViewMatcherException}</a>.
+    </p>
+      </li>
+      <li>Using the Hamcrest
+      <a href="http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html"
+         class="external-link">{@code Matchers}</a> class. You can use the
+      {@code allOf()} methods to combine multiple matchers, such as
+      {@code containsString()} and {@code instanceOf()}. This approach allows you to
+      filter the match results more narrowly, as shown in the following example:
+<pre>
+onView(allOf(withId(R.id.button_signin), withText("Sign-in")));
+</pre>
+<p>You can use the {@code not} keyword to filter for views that don't correspond to the matcher, as
+shown in the following example:</p>
+<pre>
+onView(allOf(withId(R.id.button_signin), not(withText("Sign-out"))));
+</pre>
+<p>To use these methods in your test, import the {@code org.hamcrest.Matchers} package. To
+learn more about Hamcrest matching, see the
+<a href="http://hamcrest.org/" class="external-link">Hamcrest site</a>.
+</p>
+      </li>
+    </ul>
+
+    <p>
+      To improve the performance of your Espresso tests, specify the minimum matching information
+      needed to find your target view. For example, if a view is uniquely identifiable by its
+      descriptive text, you do not need to specify that it is also assignable from the
+      {@link android.widget.TextView} instance.
+    </p>
+
+    <h4 id="#locating-adpeterview-view">
+      Locating a view in an AdapterView
+    </h4>
+
+    <p>
+      In an {@link android.widget.AdapterView} widget, the view is dynamically populated with child
+      views at runtime. If the target view you want to test is inside an
+      {@link android.widget.AdapterView}
+      (such as a {@link android.widget.ListView}, {@link android.widget.GridView}, or
+      {@link android.widget.Spinner}), the
+<a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onView(org.hamcrest.Matcher<android.view.View>)">
+  {@code onView()}</a> method might not work because only a
+      subset of the views may be loaded in the current view hierarchy.
+    </p>
+
+    <p>
+      Instead, call the <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+      method to obtain a
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html">
+      {@code DataInteraction}</a>
+      object to access the target view element. Espresso handles loading the target view element
+      into the current view hierarchy. Espresso also takes care of scrolling to the target element,
+      and putting the element into focus.
+    </p>
+
+    <p class="note">
+      <strong>Note</strong>: The
+  <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+      method does not check if if the item you specified corresponds with a view. Espresso searches
+      only the current view hierarchy. If no match is found, the method throws a
+      <a href="{@docRoot}reference/android/support/test/espresso/NoMatchingViewException.html">
+        {@code NoMatchingViewException}</a>.
+    </p>
+
+    <p>
+      The following code snippet shows how you can use the
+      <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+      method together
+      with Hamcrest matching to search for a specific row in a list that contains a given string.
+      In this example, the {@code LongListActivity} class contains a list of strings exposed
+      through a {@link android.widget.SimpleAdapter}.
+    </p>
+
+<pre>
+onData(allOf(is(instanceOf(Map.class)),
+        hasEntry(equalTo(LongListActivity.ROW_TEXT), is(str))));
+</pre>
+
+    <h3 id="perform-actions">
+      Performing Actions
+    </h3>
+
+    <p>
+      Call the <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code ViewInteraction.perform()}</a>
+      or
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#perform(android.support.test.espresso.ViewAction...)">{@code DataInteraction.perform()}</a>
+      methods to
+      simulate user interactions on the UI component. You must pass in one or more
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
+      objects as arguments. Espresso fires each action in sequence according to
+      the given order, and executes them in the main thread.
+    </p>
+
+    <p>
+      The
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html">{@code ViewActions}</a>
+      class provides a list of helper methods for specifying common actions.
+      You can use these methods as convenient shortcuts instead of creating and configuring
+      individual <a href="{@docRoot}reference/android/support/test/espresso/ViewAction.html">{@code ViewAction}</a>
+      objects. You can specify such actions as:
+    </p>
+
+    <ul>
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#click()">{@code ViewActions.click()}</a>:
+       Clicks on the view.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#typeText(java.lang.String)">{@code ViewActions.typeText()}</a>:
+       Clicks on a view and enters a specified string.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>:
+       Scrolls to the view. The
+        target view must be subclassed from {@link android.widget.ScrollView}
+        and the value of its
+        <a href="http://developer.android.com/reference/android/view/View.html#attr_android:visibility">{@code android:visibility}</a>
+        property must be {@link android.view.View#VISIBLE}. For views that extend
+        {@link android.widget.AdapterView} (for example,
+        {@link android.widget.ListView}),
+        the
+        <a href="{@docRoot}reference/android/support/test/espresso/Espresso.html#onData(org.hamcrest.Matcher<java.lang.Object>)">{@code onData()}</a>
+        method takes care of scrolling for you.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#pressKey(int)">{@code ViewActions.pressKey()}</a>:
+       Performs a key press using a specified keycode.
+      </li>
+
+      <li>
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#clearText()">{@code ViewActions.clearText()}</a>:
+      Clears the text in the target view.
+      </li>
+    </ul>
+
+    <p>
+      If the target view is inside a {@link android.widget.ScrollView}, perform the
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
+      action first to display the view in the screen before other proceeding
+      with other actions. The
+      <a href="{@docRoot}reference/android/support/test/espresso/action/ViewActions.html#scrollTo()">{@code ViewActions.scrollTo()}</a>
+      action will have no effect if the view is already displayed.
+    </p>
+
+    <h3 id="verify-results">
+      Verifying Results
+    </h3>
+
+    <p>
+      Call the
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code ViewInteraction.check()}</a>
+      or
+      <a href="{@docRoot}reference/android/support/test/espresso/DataInteraction.html#check(android.support.test.espresso.ViewAssertion)">{@code DataInteraction.check()}</a>
+      method to assert
+      that the view in the UI matches some expected state. You must pass in a
+      <a href="{@docRoot}reference/android/support/test/espresso/ViewAssertion.html">
+      {@code ViewAssertion}</a> object as the argument. If the assertion fails, Espresso throws
+      an {@link junit.framework.AssertionFailedError}.
+    </p>
+
+    <p>
+      The
+  <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html">{@code ViewAssertions}</a>
+      class provides a list of helper methods for specifying common
+      assertions. The assertions you can use include:
+    </p>
+
+    <ul>
+      <li>
+        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#doesNotExist()">{@code doesNotExist}</a>:
+Asserts that there is no view matching the specified criteria in the current view hierarchy.
+      </li>
+
+      <li>
+        <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#matches(org.hamcrest.Matcher&lt;? super android.view.View&gt;)">{@code matches}</a>:
+        Asserts that the specified view exists in the current view hierarchy
+        and its state matches some given Hamcrest matcher.
+      </li>
+
+      <li>
+       <a href="{@docRoot}reference/android/support/test/espresso/assertion/ViewAssertions.html#selectedDescendantsMatch(org.hamcrest.Matcher&lt;android.view.View&gt;, org.hamcrest.Matcher&lt;android.view.View&gt;)">{@code selectedDescendentsMatch}</a>
+       : Asserts that the specified children views for a
+        parent view exist, and their state matches some given Hamcrest matcher.
+      </li>
+    </ul>
+
+    <p>
+      The following code snippet shows how you might check that the text displayed in the UI has
+      the same value as the text previously entered in the
+      {@link android.widget.EditText} field.
+    </p>
+<pre>
+public void testChangeText_sameActivity() {
+    // Type text and then press the button.
+    ...
+
+    // Check that the text was changed.
+    onView(withId(R.id.textToBeChanged))
+            .check(matches(withText(STRING_TO_BE_TYPED)));
+}
+</pre>
+
+<h2 id="run">Run Espresso Tests on a Device or Emulator</h2>
+
+    <p>
+      To run Espresso tests, you must use the
+      <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+      class provided in the
+      <a href="{@docRoot}tools/testing-support-library/index.html">
+      Android Testing Support Library</a> as your default test runner. The
+      <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for
+      Gradle</a> provides a default directory ({@code src/androidTest/java}) for you to store the
+      instrumented test classes and test suites that you want to run on a device. The
+      plug-in compiles the test code in that directory and then executes the test app using
+      the configured test runner class.
+    </p>
+
+    <p>
+      To run Espresso tests in your Gradle project:
+    </p>
+
+    <ol>
+      <li>Specify
+        <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+        as the default test instrumentation runner in
+      your {@code build.gradle} file:
+
+  <pre>
+android {
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+}</pre>
+      </li>
+      <li>Run your tests from the command-line by calling the the {@code connectedCheck}
+        (or {@code cC}) task:
+  <pre>
+./gradlew cC</pre>
+      </li>
+    </ol>
\ No newline at end of file
diff --git a/docs/html/training/testing/ui-testing/index.jd b/docs/html/training/testing/ui-testing/index.jd
new file mode 100644
index 0000000..20422f7
--- /dev/null
+++ b/docs/html/training/testing/ui-testing/index.jd
@@ -0,0 +1,76 @@
+page.title=Automating User Interface Tests
+page.tags=testing
+
+trainingnavtop=true
+startpage=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+        <h2>
+          You should also read
+        </h2>
+
+        <ul>
+          <li>
+            <a href="{@docRoot}tools/testing-support-library/index.html">Testing Support Library</a>
+          </li>
+        </ul>
+</div>
+</div>
+
+<p>User interface (UI) testing lets you ensure that your app meets its functional requirements
+and achieves a high standard of quality such that it is more likely to be successfully adopted by
+users.</p>
+
+<p>One approach to UI testing is to simply have a human tester perform a set of user operations on
+the target app and verify that it is behaving correctly. However, this manual approach can be
+time-consuming, tedious, and error-prone. A more efficient approach is to write your UI
+tests such that user actions are performed in an automated way. The automated approach allows
+you to run your tests quickly and reliably in a repeatable manner.</p>
+
+<p class="note"><strong>Note: </strong>It is strongly encouraged that you use
+<a href="{@docRoot}sdk/installing/studio.html">Android Studio</a> for
+building your test apps, because it provides project setup, library inclusion, and packaging
+conveniences. This class assumes you are using Android Studio.</p>
+
+<p>To automate UI tests with Android Studio, you implement your test code in a separate
+Android test folder ({@code src/androidTest/java}). The
+<a href="{@docRoot}tools/building/plugin-for-gradle.html">Android
+Plug-in for Gradle</a> builds a test app based on your test code, then loads the test app on the
+same device as the target app. In your test code, you can use UI testing frameworks to
+simulate user interactions on the target app, in order to perform testing tasks that cover specific
+usage scenarios.</p>
+
+<p>For testing Android apps, you typically create these types of automated UI tests:</p>
+
+<ul>
+<li><em>UI tests that span a single app:</em> This type of test verifies that the target app behaves
+as expected when a user performs a specific action or enters a specific input in its activities.
+It allows you to check that the target app returns the correct UI output in response
+to user interactions in the app’s activities. UI testing frameworks like Espresso allow you to
+programmatically simulate user actions and test complex intra-app user interactions.</li>
+<li><em>UI tests that span multiple apps:</em> This type of test verifies the correct behavior of
+interactions between different user apps or between user apps and system apps. For example, you
+might want to test that your camera app shares images correctly with a 3rd-party social media app,
+or with the default Android Photos app. UI testing frameworks that support cross-app interactions,
+such as UI Automator, allow you to create tests for such scenarios.</li>
+</ul>
+
+<p>The lessons in this class teach you how to use the tools and APIs in the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
+to build these types of automated tests. Before you begin building tests using these
+APIs, you must install the Android Testing Support Library, as described in
+<a href="{@docRoot}tools/testing-support-library/index.html#setup">Downloading the Android
+Testing Support Library</a>.</p>
+
+<h2>Lessons</h2>
+<dl>
+  <dt><strong><a href="espresso-testing.html">
+Testing UI for a Single App</a></strong></dt>
+    <dd>Learn how to test UI in a single app by using the Espresso testing framework.</dd>
+  <dt><strong><a href="uiautomator-testing.html">
+Testing UI for Multiple Apps</a></strong></dt>
+    <dd>Learn how to test UI in multiple apps by using the UI Automator testing framework</dd>
+</dl>
\ No newline at end of file
diff --git a/docs/html/training/testing/ui-testing/uiautomator-testing.jd b/docs/html/training/testing/ui-testing/uiautomator-testing.jd
new file mode 100644
index 0000000..e314b70
--- /dev/null
+++ b/docs/html/training/testing/ui-testing/uiautomator-testing.jd
@@ -0,0 +1,520 @@
+page.title=Testing UI for Multiple Apps
+page.tags=testing,ui automator
+trainingnavtop=true
+
+@jd:body
+
+<!-- This is the training bar -->
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+
+  <ul>
+    <li>Android 4.3 (API level 18) or higher</li>
+    <li><a href="{@docRoot}tools/testing-support-library/index.html">
+      Android Testing Support Library</a></li>
+  </ul>
+
+  <h2>This lesson teaches you to</h2>
+
+  <ol>
+    <li><a href="#setup">Set Up UI Automator</a></li>
+    <li><a href="#build">Create a UI Automator Test Class</a></li>
+    <li><a href="#run">Run UI Automator Tests on a Device or Emulator</a></li>
+  </ol>
+
+  <h2>You should also read</h2>
+
+  <ul>
+    <li><a href="{@docRoot}reference/android/support/test/package-summary.html">
+UI Automator API Reference</a></li>
+  </ul>
+
+  <h2>Try it out</h2>
+
+  <ul>
+    <li><a href="https://github.com/googlesamples/android-testing"
+class="external-link">UI Automator Code Samples</a></li>
+  </ul>
+</div>
+</div>
+
+<p>A user interface (UI) test that involves user interactions across multiple apps lets you
+verify that your app behaves correctly when the user flow crosses into other apps or into the
+system UI. An example of such a user flow is a messaging app that lets the user enter a text
+message, launches the Android contact picker so that the users can select recipients to send the
+message to, and then returns control to the original app for the user to submit the message.</p>
+
+<p>This lesson covers how to write such UI tests using the
+UI Automator testing framework provided by the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
+The UI Automator APIs let you interact with visible elements on a device, regardless of
+which {@link android.app.Activity} is in focus. Your test can look up a UI component by using
+convenient descriptors such as the text displayed in that component or its content description. UI
+Automator tests can run on devices running Android 4.3 (API level 18) or higher.</p>
+
+<p>The UI Automator testing framework is an instrumentation-based API and works
+with the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
+  {@code AndroidJUnitRunner}</a>
+test runner.
+</p>
+
+<h2 id="setup">Set Up UI Automator</h2>
+<p>Before you begin using UI Automator, you must:</p>
+
+  <ul>
+      <li>
+        <strong>Install the Android Testing Support Library</strong>. The UI Automator API is
+        located under the {@code com.android.support.test.uiautomator} package. These classes allow
+        you to create tests that use the Espresso testing framework. To learn how to install the
+        library, see <a href="{@docRoot}tools/testing-support-library/index.html#setup">
+        Testing Support Library Setup</a>.
+      </li>
+
+      <li>
+        <strong>Set up your project structure.</strong> In your Gradle project, the source code for
+        the target app that you want to test is typically placed under the {@code app/src/main}
+        folder. The source code for instrumentation tests, including
+        your UI Automator tests, must be placed under the <code>app/src/androidTest</code> folder.
+        To learn more about setting up your project directory, see
+        <a href="{@docRoot}tools/projects/index.html">Managing Projects</a>.
+      </li>
+
+      <li>
+        <strong>Specify your Android testing dependencies</strong>. In order for the
+        <a href="{@docRoot}tools/building/plugin-for-gradle.html">Android Plug-in for Gradle</a> to
+        correctly build and run your UI Automator tests, you must specify the following libraries in
+        the {@code build.gradle} file of your Android app module:
+
+        <pre>
+dependencies {
+    androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
+    androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0'
+}
+</pre>
+      </li>
+  </ul>
+
+<p>To optimize your UI Automator testing, you should first inspect the target app’s UI components
+and ensure that they are accessible. These optimization tips are described in the next two
+sections.</p>
+
+<h3 id="inspecting-ui">Inspecting the UI on a device</h3>
+<p>Before designing your test, inspect the UI components that are visible on the device. To
+ensure that your UI Automator tests can access these components, check that these components
+have visible text labels,
+<a href="http://developer.android.com/reference/android/view/View.html#attr_android:contentDescription">
+{@code android:contentDescription}</a>
+values, or both.</p>
+
+<p>The {@code uiautomatorviewer} tool provides a convenient visual interface to inspect the layout
+hierarchy and view the properties of UI components that are visible on the foreground of the device.
+This information lets you create more fine-grained tests using UI Automator. For example, you can
+create a UI selector that matches a specific visible property. </p>
+
+<p>To launch the {@code uiautomatorviewer} tool:</p>
+
+<ol>
+  <li>Launch the target app on a physical device.</li>
+  <li>Connect the device to your development machine.</li>
+  <li>Open a terminal window and navigate to the {@code &lt;android-sdk&gt;/tools/} directory.</li>
+  <li>Run the tool with this command:
+<pre>$ uiautomatorviewer</pre>
+  </li>
+</ol>
+
+<p>To view the UI properties for your application:</p>
+
+<ol>
+  <li>In the {@code uiautomatorviewer} interface, click the <strong>Device Screenshot</strong>
+button.</li>
+  <li>Hover over the snapshot in the left-hand panel to see the UI components identified by the
+{@code uiautomatorviewertool}. The properties are listed in the lower right-hand panel and the
+layout hierarchy in the upper right-hand panel.</li>
+  <li>Optionally, click on the <strong>Toggle NAF Nodes</strong> button to see UI components that
+are non-accessible to UI Automator. Only limited information may be available for these
+components.</li>
+</ol>
+
+<p>To learn about the common types of UI components provided by Android, see
+<a href="{@docRoot}guide/topics/ui/index.html">User Interface</a>.</p>
+
+<h3>Ensuring your Activity is accessible</h3>
+<p>The UI Automator test framework depends on the accessibility features of the Android framework
+to look up individual UI elements. As a developer, you should implement these minimum
+optimizations in your {@link android.app.Activity} to support UI Automator:</p>
+
+<ul>
+<li>Use the
+<a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">
+  {@code android:contentDescription}</a>
+attribute to label the {@link android.widget.ImageButton}, {@link android.widget.ImageView},
+{@link android.widget.CheckBox} and other user interface controls.</li>
+<li>Provide an <a href="{@docRoot}reference/android/widget/TextView.html#attr_android:hint">{@code android:hint}</a>
+attribute instead of a content description for {@link android.widget.EditText} fields.</li>
+<li>Associate an <a href="http://developer.android.com/reference/android/widget/TextView.html#attr_android:hint">
+  {@code android:hint}</a>
+attribute with any graphical icons used by controls that provide feedback to the user
+(for example, status or state information).</li>
+<li>Use the {@code uiautomatorviewer} tool to ensure that the UI component is accessible to the
+testing framework. You can also test the application by turning on accessibility services like
+TalkBack and Explore by Touch, and try using your application using only directional controls.</li>
+</ul>
+
+<p>Generally, app developers get accessibility support for free, courtesy of
+the {@link android.view.View} and {@link android.view.ViewGroup}
+classes. However, some apps use custom view elements to provide a richer user experience. Such
+custom elements won't get the accessibility support that is provided by the standard Android UI
+elements. If this applies to your app, make sure that it exposes the custom-drawn UI element to
+Android accessibility services by implementing the
+{@link android.view.accessibility.AccessibilityNodeProvider} class.</p>
+
+<p>If the custom view element contains a single element, make it accessible by
+<a href="{@docRoot}guide/topics/ui/accessibility/apps.html#accessibility-methods">implementing
+accessibility API methods</a>.
+If the custom view contains elements that are not views themselves (for example, a
+{@link android.webkit.WebView}, make sure it implements the
+{@link android.view.accessibility.AccessibilityNodeProvider} class. For container views that
+extend an existing container implementation
+(for example, a {@link android.widget.ListView}), implementing
+{@link android.view.accessibility.AccessibilityNodeProvider} is not necessary.</p>
+
+<p>For more information about implementing and testing accessibility, see
+<a href="{@docRoot}guide/topics/ui/accessibility/apps.html">Making Applications Accessible</a>.</p>
+
+<h2 id="build">Create a UI Automator Test Class</h2>
+
+<p>To build a UI Automator test, create a class that extends
+{@link android.test.InstrumentationTestCase}. Implement the following programming model in your
+UI Automator test class:</p>
+
+<ol>
+<li>Get a
+  <a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+  object to access the device you want to test, by calling the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#getInstance(android.app.Instrumentation)">
+{@code getInstance()}</a>
+method and passing it an {@link android.app.Instrumentation} object as the argument.</li>
+<li>Get a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+object to access a UI component that is displayed on the device
+	(for example, the current view in the foreground), by calling the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">
+  {@code findObject()}</a>
+method.
+</li>
+<li>Simulate a specific user interaction to perform on that UI component, by calling a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+method; for example, call
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#performMultiPointerGesture(android.view.MotionEvent.PointerCoords[]...)">
+  {@code performMultiPointerGesture()}</a>
+to simulate a multi-touch gesture, and
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">{@code setText()}</a>
+to edit a text field. You can call on the APIs in steps 2 and 3 repeatedly as necessary to test
+more complex user interactions that involve multiple UI components or sequences of user actions.</li>
+<li>Check that the UI reflects the expected state or behavior, after these user interactions are
+	performed. </li>
+</ol>
+
+<p>These steps are covered in more detail in the sections below.</p>
+
+<h3 id="accessing-ui-components">Accessing UI Components</h3>
+<p>The
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+  object is the primary way you access and manipulate the state of the
+device. In your tests, you can call
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+methods to check for the state of various properties, such as current orientation or display size.
+Your test can use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+object to perform device-level actions, such as forcing the device into a specific rotation,
+pressing D-pad hardware buttons, and pressing the Home and Menu buttons.</p>
+
+<p>It’s good practice to start your test from the Home screen of the device. From the Home screen
+(or some other starting location you’ve chosen in the device), you can call the methods provided by
+the UI Automator API to select and interact with specific UI elements. </p>
+
+<p>The following code snippet shows how your test might get an instance of
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html">{@code UiDevice}</a>
+and simulate a Home button press:</p>
+
+<pre>
+import android.test.InstrumentationTestCase;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.By;
+
+public class CalculatorUiTest extends InstrumentationTestCase {
+
+    private UiDevice mDevice;
+
+    public void setUp() {
+        // Initialize UiDevice instance
+        mDevice = UiDevice.getInstance(getInstrumentation());
+
+        // Start from the home screen
+        mDevice.pressHome();
+        mDevice.wait(Until.hasObject(By.pkg(getHomeScreenPackage()).depth(0)),
+    }
+}
+</pre>
+
+<p>Use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiDevice.html#findObject(android.support.test.uiautomator.UiSelector)">{@code findObject()}</a>
+method to retrieve a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+which represents a view that matches a given selector criteria. You can reuse the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+instances that you have created in other parts of your app testing, as needed. Note that the
+UI Automator test framework searches the current display for a match every time your test uses a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+instance to click on a UI element or query a property.</p>
+
+<p>The following snippet shows how your test might construct
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+instances that represent a Cancel button and a OK button in an app.</p>
+
+<pre>
+UiObject cancelButton = mDevice.findObject(new UiSelector()
+        .text("Cancel"))
+        .className("android.widget.Button"));
+UiObject okButton = mDevice.findObject(new UiSelector()
+        .text("OK"))
+        .className("android.widget.Button"));
+
+// Simulate a user-click on the OK button, if found.
+if(okButton.exists() &#38;&#38; okButton.isEnabled()) {
+    okButton.click();
+}
+</pre>
+
+<h4 id="specifying-selector">Specifying a selector</h4>
+<p>If you want to access a specific UI component in an app, use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
+class. This class represents a query for specific elements in the
+currently displayed UI. </p>
+
+<p>If more than one matching element is found, the first matching element in the layout hierarchy
+is returned as the target
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>.
+When constructing a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>,
+you can chain together multiple properties to refine your search. If no matching UI element is
+found, a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObjectNotFoundException.html">
+{@code UiAutomatorObjectNotFoundException}</a> is thrown. </p>
+
+<p>You can use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html#childSelector(android.support.test.uiautomator.UiSelector)">{@code childSelector()}</a>
+method to nest multiple
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
+instances. For example, the following code example shows how your test might specify a search to
+find the first {@link android.widget.ListView} in the currently displayed UI, then search within that
+{@link android.widget.ListView} to find a UI element with the text property Apps.</p>
+
+<pre>
+UiObject appItem = new UiObject(new UiSelector()
+        .className("android.widget.ListView")
+        .instance(1)
+        .childSelector(new UiSelector()
+        .text("Apps")));
+</pre>
+
+<p>As a best practice, when specifying a selector, you should use a Resource ID (if one is assigned
+to a UI element) instead of a text element or content-descriptor. Not all elements have a text
+element (for example, icons in a toolbar). Text selectors are brittle and can lead to test failures
+if there are minor changes to the UI. They may also not scale across different languages; your text
+selectors may not match translated strings.</p>
+
+<p>It can be useful to specify the object state in your selector criteria. For example, if you want
+to select a list of all checked elements so that you can uncheck them, call the
+<a href="{@docRoot}reference/android/support/test/uiautomator/By.html#checked(boolean)">
+{@code checked()}</a>
+method with the argument set to {@code true}.</p>
+
+<h3 id="performing-actions">Performing Actions</h3>
+
+<p>Once your test has obtained a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+object, you can call the methods in the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>
+class to perform user interactions on the UI component represented by that
+object. You can specify such actions as:</p>
+
+<ul>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#click()">
+  {@code click()}</a>
+: Clicks the center of the visible bounds of the UI element.</li>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#dragTo(int, int, int)">
+  {@code dragTo()}</a>
+: Drags this object to arbitrary coordinates.</li>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#setText(java.lang.String)">
+  {@code setText()}</a>
+: Sets the text in an editable field, after clearing the field's content.
+Conversely, the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#clearTextField()">
+  {@code clearTextField()}</a>
+method clears the existing text in an editable field.</li>
+<li>
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeUp(int)">
+  {@code swipeUp()}</a>
+: Performs the swipe up action on the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html">{@code UiObject}</a>.
+Similarly, the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeDown(int)">
+  {@code swipeDown()}</a>,
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeLeft(int)">
+  {@code swipeLeft()}</a>, and
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiObject.html#swipeRight(int)">
+  {@code swipeRight()}</a>
+methods perform corresponding actions.</li>
+</ul>
+
+<p>The UI Automator testing framework allows you to send an
+{@link android.content.Intent}
+or launch an {@link android.app.Activity}
+without using shell commands, by getting a
+{@link android.content.Context}
+object through
+{@link android.app.Instrumentation#getContext() getContext()}.</p>
+
+<p>The following snippet shows how your test can use an
+{@link android.content.Intent} to launch the app under test. This approach is useful when you are
+only interested in testing the calculator app, and don't care about the launcher.</p>
+
+<pre>
+public void setUp() {
+    ...
+
+    // Launch a simple calculator app
+    Context context = getInstrumentation().getContext();
+    Intent intent = context.getPackageManager()
+            .getLaunchIntentForPackage(CALC_PACKAGE);
+    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+            // Clear out any previous instances
+    context.startActivity(intent);
+    mDevice.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
+}
+</pre>
+
+<h4 id="actions-on-collections">Performing actions on collections</h4>
+
+<p>Use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
+  {@code UiCollection}</a>
+class if you want to simulate user interactions on a
+collection of items (for example, songs in a music album or a list of emails in an Inbox). To
+create a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
+  {@code UiCollection}</a>
+object, specify a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiSelector.html">{@code UiSelector}</a>
+that searches for a
+UI container or a wrapper of other child UI elements, such as a layout view that contains child UI
+elements.</p>
+
+<p>The following code snippet shows how your test might construct a
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiCollection.html">
+  {@code UiCollection}</a>
+to represent a video album that is displayed within a {@link android.widget.FrameLayout}:</p>
+
+<pre>
+UiCollection videos = new UiCollection(new UiSelector()
+        .className("android.widget.FrameLayout"));
+
+// Retrieve the number of videos in this collection:
+int count = videos.getChildCount(new UiSelector()
+        .className("android.widget.LinearLayout"));
+
+// Find a specific video and simulate a user-click on it
+UiObject video = videos.getChildByText(new UiSelector()
+        .className("android.widget.LinearLayout"), "Cute Baby Laughing");
+video.click();
+
+// Simulate selecting a checkbox that is associated with the video
+UiObject checkBox = video.getChild(new UiSelector()
+        .className("android.widget.Checkbox"));
+if(!checkBox.isSelected()) checkbox.click();
+</pre>
+
+<h4 id="actions-on-scrollable-views">Performing actions on scrollable views</h4>
+<p>Use the
+<a href="{@docRoot}reference/android/support/test/uiautomator/UiScrollable.html">
+  {@code UiScrollable}</a>
+class to simulate vertical or horizontal scrolling across a display. This technique is helpful when
+a UI element is positioned off-screen and you need to scroll to bring it into view.</p>
+
+<p>The following code snippet shows how to simulate scrolling down the Settings menu and clicking
+on an About tablet option:</p>
+
+<pre>
+UiScrollable settingsItem = new UiScrollable(new UiSelector()
+        .className("android.widget.ListView"));
+UiObject about = settingsItem.getChildByText(new UiSelector()
+        .className("android.widget.LinearLayout"), "About tablet");
+about.click();
+</pre>
+
+<h3 id="verifying-results">Verifying Results</h3>
+<p>The {@link android.test.InstrumentationTestCase} extends {@link junit.framework.TestCase}, so
+you can use standard JUnit <a href="http://junit.org/javadoc/latest/org/junit/Assert.html"
+class="external-link">{@code Assert}</a> methods to test
+that UI components in the app return the expected results. </p>
+
+<p>The following snippet shows how your test can locate several buttons in a calculator app, click
+on them in order, then verify that the correct result is displayed.</p>
+
+<pre>
+private static final String CALC_PACKAGE = "com.myexample.calc";
+
+public void testTwoPlusThreeEqualsFive() {
+    // Enter an equation: 2 + 3 = ?
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("two")).click();
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("plus")).click();
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("three")).click();
+    mDevice.findObject(new UiSelector()
+            .packageName(CALC_PACKAGE).resourceId("equals")).click();
+
+    // Verify the result = 5
+    UiObject result = mDevice.findObject(By.res(CALC_PACKAGE, "result"));
+    assertEquals("5", result.getText());
+}
+</pre>
+
+<h2 id="run">Run UI Automator Tests on a Device or Emulator</h2>
+<p>UI Automator tests are based on the {@link android.app.Instrumentation} class. The
+<a href="https://developer.android.com/tools/building/plugin-for-gradle.html">
+  Android Plug-in for Gradle</a>
+provides a default directory ({@code src/androidTest/java}) for you to store the instrumented test
+classes and test suites that you want to run on a device. The plug-in compiles the test
+code in that directory and then executes the test app using a test runner class. You are
+strongly encouraged to use the
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+class provided in the
+<a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>
+as your default test runner. </p>
+
+<p>To run UI Automator tests in your Gradle project:</p>
+
+<ol>
+<li>Specify
+<a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">{@code AndroidJUnitRunner}</a>
+as the default test instrumentation runner in your {@code build.gradle} file:
+<pre>
+android {
+    defaultConfig {
+        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+    }
+}</pre>
+</li>
+<li>Run your tests from the command-line by calling the {@code connectedCheck}
+  (or {@code cC}) task:
+<pre>./gradlew cC</pre>
+</li>
+</ol>
\ No newline at end of file
diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs
index 11ae1a6..3ee7ab7 100644
--- a/docs/html/training/training_toc.cs
+++ b/docs/html/training/training_toc.cs
@@ -998,10 +998,25 @@
            Building TV Games</a>
       </li>
 
-      <li>
-        <a href="<?cs var:toroot ?>training/tv/tif/index.html"
+      <li class="nav-section">
+        <div class="nav-section-header">
+          <a href="<?cs var:toroot ?>training/tv/tif/index.html"
            description="How to build Live TV apps.">
            Building Live TV Apps</a>
+        </div>
+        <ul>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/tvinput.html">
+              Developing a TV Input Service</a>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/channel.html">
+              Working with Channel Data</a>
+          </li>
+          <li>
+            <a href="<?cs var:toroot ?>training/tv/tif/ui.html">
+              Managing User Interaction</a>
+          </li>
+        </ul>
       </li>
 
       <li>
@@ -1825,6 +1840,24 @@
         </ul>
       </li>
     </ul>
+    <ul>
+      <li class="nav-section">
+      <div class="nav-section-header"><a href="<?cs var:toroot ?>training/testing/ui-testing/index.html"
+         description="How to automate your user interface tests for Android apps.">
+            Automating UI Tests
+          </a></div>
+        <ul>
+          <li><a href="<?cs var:toroot ?>training/testing/ui-testing/espresso-testing.html">
+            <span class="en">Testing UI for a Single App</span>
+          </a>
+          </li>
+          <li><a href="<?cs var:toroot ?>training/testing/ui-testing/uiautomator-testing.html">
+            <span class="en">Testing UI for Multiple Apps</span>
+          </a>
+          </li>
+        </ul>
+      </li>
+    </ul>
   </li>
   <!-- End best Testing -->
 
diff --git a/docs/html/training/tv/tif/channel.jd b/docs/html/training/tv/tif/channel.jd
new file mode 100644
index 0000000..999f1ca
--- /dev/null
+++ b/docs/html/training/tv/tif/channel.jd
@@ -0,0 +1,239 @@
+page.title=Working with Channel Data
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#permission">Get Permission</a></li>
+    <li><a href="#register">Register Channels in the Database</a></li>
+    <li><a href="#update">Update Channel Data</a></li>
+  </ol>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>Your TV input must provide Electronic Program Guide (EPG) data for at least one channel in its
+setup activity. You should also periodically update that data, with consideration for the size of
+the update and the processing thread that handles it. This lesson discusses creating and updating
+channel and program data on the system database with these considerations in mind.</p>
+
+<p>&nbsp;</p>
+
+<h2 id="permission">Get Permission</h2>
+
+<p>In order for your TV input to work with EPG data, it must declare the
+read and write permissions in its Android manifest file as follows:</p>
+
+<pre>
+&lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
+&lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
+</pre>
+
+<h2 id="register">Register Channels in the Database</h2>
+
+<p>The Android TV system database maintains records of channel data for TV inputs. In your setup
+activity, for each of your channels, you must map your channel data to the following fields of the
+{@link android.media.tv.TvContract.Channels} class:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NAME} - the displayed name of the
+  channel</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER} - the displayed channel
+  number</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_INPUT_ID} - the ID of the TV input service</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_TYPE} - the channel's service type</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TYPE} - the channel's broadcast standard
+  type</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_VIDEO_FORMAT} - the default video format
+  for the channel</li>
+</ul>
+
+<p>Although the TV input framework is generic enough to handle both traditional broadcast and
+over-the-top (OTT) content without any distinction, you may want to define the following columns in
+addition to those above to better identify traditional broadcast channels:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_ORIGINAL_NETWORK_ID} - the television
+  network ID</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_ID} - the service ID</li>
+  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TRANSPORT_STREAM_ID} - the transport stream
+  ID</li>
+</ul>
+
+<p>For internet streaming based TV inputs, assign your own values to the above accordingly so that
+each channel can be identified uniquely.</p>
+
+<p>Pull your channel metadata (in XML, JSON, or whatever) from your backend server, and in your setup
+activity map the values to the system database as follows:</p>
+
+<pre>
+ContentValues values = new ContentValues();
+
+values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.mNumber);
+values.put(Channels.COLUMN_DISPLAY_NAME, channel.mName);
+values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.mOriginalNetworkId);
+values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.mTransportStreamId);
+values.put(Channels.COLUMN_SERVICE_ID, channel.mServiceId);
+values.put(Channels.COLUMN_VIDEO_FORMAT, channel.mVideoFormat);
+
+Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
+</pre>
+
+<p>In the example above, <code>channel</code> is an object which holds channel metadata from the
+backend server.</p>
+
+<h3 id="art">Present Channel and Program Information</h2>
+
+<p>The system TV app presents channel and program information to users as they flip through channels,
+as shown in figure 1. To make sure the channel and program information works with the system TV app's
+channel and program information presenter, follow the guidelines below.</p>
+
+<ol>
+<li><strong>Channel number</strong> ({@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER})
+<li><strong>Icon</strong>
+(<a href="guide/topics/manifest/application-element.html#icon"><code>android:icon</code></a> in the
+TV input's manifest)</li>
+<li><strong>Program description</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_SHORT_DESCRIPTION})
+<li><strong>Program title</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_TITLE})</li>
+<li><strong>Channel logo</strong> ({@link android.media.tv.TvContract.Channels.Logo})
+  <ul>
+    <li>Use the color #EEEEEE to match the surrounding text</li>
+    <li>Don't include padding
+  </ul></li>
+<li><strong>Poster art</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_POSTER_ART_URI})
+  <ul>
+    <li>Aspect ratio between 16:9 and 4:3</li>
+  </ul>
+</ol>
+
+<img src="{@docRoot}images/tv/channel-info.png" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> The system TV app channel and program information presenter.
+</p>
+
+<p>The system TV app provides the same information through the program guide, including poster art,
+as shown in figure 2.</p>
+
+<img src="{@docRoot}images/tv/prog-guide.png" id="figure2">
+<p class="img-caption">
+  <strong>Figure 2.</strong> The system TV app program guide.
+</p>
+
+<h2 id="update">Update Channel Data</h2>
+
+<p>When updating existing channel data, use the
+{@link android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues,
+java.lang.String, java.lang.String[]) update()}
+method instead of deleting and re-adding the data. You can identify the current version of the data
+by using {@link android.media.tv.TvContract.Channels#COLUMN_VERSION_NUMBER Channels.COLUMN_VERSION_NUMBER}
+and {@link android.media.tv.TvContract.Programs#COLUMN_VERSION_NUMBER Programs.COLUMN_VERSION_NUMBER}
+when choosing the records to update.</p>
+
+<p class="note"><strong>Note:</strong> Adding channel data to the {@link android.content.ContentProvider}
+can take time. Only add current programs (those within two hours of the current time) when you update,
+and use a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">Sync Adapter</a> to
+update the rest of the channel data in the background. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV Live TV Sample App</a> for an example.</p>
+
+<h3 id="batch">Batch Loading Channel Data</h3>
+
+<p>When updating the system database with a large amount of channel data, use the {@link android.content.ContentResolver}
+{@link android.content.ContentResolver#applyBatch applyBatch()}
+or
+{@link android.content.ContentResolver#bulkInsert(android.net.Uri, android.content.ContentValues[]) bulkInsert()}
+method. Here's an example using {@link android.content.ContentResolver#applyBatch applyBatch()}:<p>
+
+<pre>
+ArrayList&lt;ContentProviderOperation&gt; ops = new ArrayList&lt;&gt;();
+int programsCount = mChannelInfo.mPrograms.size();
+for (int j = 0; j &lt; programsCount; ++j) {
+    ProgramInfo program = mChannelInfo.mPrograms.get(j);
+    ops.add(ContentProviderOperation.newInsert(
+            TvContract.Programs.CONTENT_URI)
+            .withValues(programs.get(j))
+            .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
+                    programStartSec * 1000)
+            .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
+                    (programStartSec + program.mDurationSec) * 1000)
+            .build());
+    programStartSec = programStartSec + program.mDurationSec;
+    if (j % 100 == 99 || j == programsCount - 1) {
+        try {
+            <strong>getContentResolver().applyBatch(TvContract.AUTHORITY, ops);</strong>
+        } catch (RemoteException | OperationApplicationException e) {
+            Log.e(TAG, "Failed to insert programs.", e);
+            return;
+        }
+        ops.clear();
+    }
+}
+</pre>
+
+<h3 id="async">Processing Channel Data Asynchronously</h3>
+
+<p>Data manipulation, such as fetching a stream from the server or accessing the database, should
+not block the UI thread. Using an {@link android.os.AsyncTask} is one
+way to perform updates asynchronously.  For example, when loading channel info from a backend server,
+you can use {@link android.os.AsyncTask} as follows:</p>
+
+<pre>
+private static class LoadTvInputTask extends AsyncTask&lt;Uri, Void, Void>&gt; {
+
+    private Context mContext;
+
+    public LoadTvInputTask(Context context) {
+        mContext = context;
+    }
+
+    &#64;Override
+    protected Void doInBackground(Uri... uris) {
+        try {
+            fetchUri(uris[0]);
+        } catch (IOException e) {
+          Log.d(“LoadTvInputTask”, “fetchUri error”);
+        }
+        return null;
+    }
+
+    private void fetchUri(Uri videoUri) throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = mContext.getContentResolver().openInputStream(videoUri);
+            XmlPullParser parser = Xml.newPullParser();
+            try {
+                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
+                parser.setInput(inputStream, null);
+                sTvInput = ChannelXMLParser.parseTvInput(parser);
+                sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
+            } catch (XmlPullParserException e) {
+                e.printStackTrace();
+            }
+        } finally {
+            if (inputStream != null) {
+                inputStream.close();
+            }
+        }
+    }
+}
+</pre>
+
+<p>If you need to update EPG data on a regular basis, consider using
+a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">
+Sync Adapter</a> or {@link android.app.job.JobScheduler} to run the update process during idle time,
+such as every day at 3:00 a.m. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
+Android TV live TV sample app</a> for an example.</p>
+
+<p>Other techniques to separate the data update tasks from the UI thread include using the
+{@link android.os.HandlerThread} class, or you may implement your own using {@link android.os.Looper}
+and {@link android.os.Handler} classes.  See <a href="{@docRoot}guide/components/processes-and-threads.html">
+Processes and Threads</a> for more information.</p>
\ No newline at end of file
diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd
index 9c10850..5739294 100644
--- a/docs/html/training/tv/tif/index.jd
+++ b/docs/html/training/tv/tif/index.jd
@@ -1,17 +1,26 @@
 page.title=Building Live TV Apps
 page.tags=tv, tif
 helpoutsWidget=true
-page.article=true
+startpage=true
 
 @jd:body
 
 <div id="tb-wrapper">
 <div id="tb">
+  <h2>Dependencies and Prerequisites</h2>
+  <ul>
+    <li>Android 5.0 (API level 21) or higher</li>
+  </ul>
   <h2>You should also read</h2>
   <ul>
     <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
       android.media.tv</a></li>
   </ul>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
 </div>
 </div>
 
@@ -44,6 +53,17 @@
   Building a TV input service for your content can help make it more accessible on TV devices.
 </p>
 
-<p>For more information about TV Input Framework, see the
-<a href="{@docRoot}reference/android/media/tv/package-summary.html">android.media.tv</a>
-reference.</p>
+<h2>Topics</h2>
+
+<dl>
+  <dt><b><a href="tvinput.html">Developing a TV Input Service</a></b></dt>
+    <dd>Learn how to develop a TV input service, which works with the system TV app.</dd>
+
+  <dt><b><a href="channel.html">Working with Channel Data</a></b></dt>
+    <dd>Learn how to describe channel and program data for the system.</dd>
+
+  <dt><b><a href="ui.html">Managing User Interaction</a></b></dt>
+    <dd>Learn how to present overlays, manage content availability, and handle content selection.</dd>
+</dl>
+
+
diff --git a/docs/html/training/tv/tif/tvinput.jd b/docs/html/training/tv/tif/tvinput.jd
new file mode 100644
index 0000000..91f8ded
--- /dev/null
+++ b/docs/html/training/tv/tif/tvinput.jd
@@ -0,0 +1,177 @@
+page.title=Developing a TV Input Service
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#manifest">Declare Your TV Input Service in the Manifest</a></li>
+    <li><a href="#tvinput">Define Your TV Input Service</a></li>
+    <li><a href="#setup">Define Setup and Settings Activities</a></li>
+  </ol>
+  <h2>You should also read</h2>
+  <ul>
+    <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
+      android.media.tv</a></li>
+    <li><a class="external-lin" href="http://source.android.com/devices/tv/index.html">
+      TV Input Framework</a></li>
+  </ul>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>A TV input service represents a media stream source, and lets you present your media content in a
+linear, broadcast TV fashion as channels and programs. With the TV input service, you can provide
+parental controls, program guide information, and content ratings. The TV input service works
+with the Android system TV app, developed for the device and immutable by third-party apps, which
+ultimately controls and presents content on the TV. See
+<a class="external-link" href="http://source.android.com/devices/tv/index.html">
+TV Input Framework</a> for more information about the framework architecture and its components.</p>
+
+<p>To develop a TV input service, you implement the following components:</p>
+
+<ul>
+  <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
+  the TV input</li>
+  <li>{@link android.media.tv.TvInputService.Session} maintains the TV input state and communicates
+  with the hosting app</li>
+  <li>{@link android.media.tv.TvContract} describes the channels and programs available to the TV
+  input</li>
+  <li>{@link android.media.tv.TvContract.Channels} represents information about a TV channel</li>
+  <li>{@link android.media.tv.TvContract.Programs} describes a TV program with data such as program
+  title and start time</li>
+  <li>{@link android.media.tv.TvTrackInfo} represents an audio, video, or subtitle track</li>
+  <li>{@link android.media.tv.TvContentRating} describes a content rating, allows for custom content
+  rating schemes</li>
+  <li>{@link android.media.tv.TvInputManager} provides an API to the system TV app and manages
+  the interaction with TV inputs and apps</li>
+</ul>
+
+<h2 id="manifest">Declare Your TV Input Service in the Manifest</h2>
+
+<p>Your app manifest must declare your {@link android.media.tv.TvInputService}. Within that
+declaration, specify the {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
+service to connect the TV input to the system. A system service (<code>TvInputManagerService</code>)
+performs the binding and has that permission. The system TV app sends requests to TV input services
+via the {@link android.media.tv.TvInputManager} interface. The service declaration must also
+include an intent filter that specifies the {@link android.media.tv.TvInputService}
+as the action to perform with the intent. Also within the service declaration, declare the service
+meta data in a separate XML resource. The service declaration, the intent filter and the service
+meta data are described in the following example.</p>
+
+<pre>
+&lt;service android:name="com.example.sampletvinput.SampleTvInput"
+    android:label="@string/sample_tv_input_label"
+    android:permission="android.permission.BIND_TV_INPUT"&gt;
+    &lt;intent-filter&gt;
+        &lt;action android:name="android.media.tv.TvInputService" /&gt;
+    &lt;/intent-filter&gt;
+    &lt;meta-data android:name="android.media.tv.input"
+      android:resource="@xml/sample_tv_input" /&gt;
+&lt;/service&gt;
+</pre>
+
+<p>Define the service meta data in separate XML file, as shown in the following example. The service
+meta data must include a setup interface that describes the TV input's initial configuration and
+channel scan. Also, the service meta data may (optionally) describe a settings activity for users to
+modify the TV input's behavior. The service meta data file is located in the XML resources directory
+for your application and must match the name of the resource in the manifest. Using the example
+manifest entries above, you would create an XML file in the location
+<code>res/xml/sample_tv_input.xml</code>, with the following contents:</p>
+
+<pre>
+&lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
+  &lt;!-- Required: activity for setting up the input --&gt;
+  android:setupActivity="com.example.sampletvinput.SampleTvInputSetupActivity"
+  &lt;!-- Optional: activity for controlling the settings --&gt;
+  android:settingsActivity="com.example.sampletvinput.SampleTvInputSettingsActivity" /&gt;
+</pre>
+
+<h2 id="tvinput">Define Your TV Input Service</h2>
+
+<div class="figure">
+<img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
+<p class="img-caption"><strong>Figure 1.</strong>TvInputService lifecycle.</p>
+</div>
+
+<p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
+{@link android.media.tv.TvInputService} implementation is a
+<a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
+(<code>TvInputManagerService</code>) is the client that binds to it. The service life cycle methods
+you need to implement are illustrated in figure 1.</p>
+
+<p>The {@link android.app.Service#onCreate()} method initializes and starts the
+{@link android.os.HandlerThread} which provides a process thread separate from the UI thread to
+handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()}
+method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle
+the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED}
+and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These
+actions describe system intents fired when the user changes the parental control settings, and when
+there is a change on the list of blocked ratings.</p>
+
+<pre>
+&#64;Override
+public void onCreate() {
+    super.onCreate();
+    mHandlerThread = new HandlerThread(getClass()
+      .getSimpleName());
+    mHandlerThread.start();
+    mDbHandler = new Handler(mHandlerThread.getLooper());
+    mHandler = new Handler();
+    mCaptioningManager = (CaptioningManager)
+      getSystemService(Context.CAPTIONING_SERVICE);
+
+    setTheme(android.R.style.Theme_Holo_Light_NoActionBar);
+
+    mSessions = new ArrayList&lt;BaseTvInputSessionImpl&gt;();
+    IntentFilter intentFilter = new IntentFilter();
+    intentFilter.addAction(TvInputManager
+      .ACTION_BLOCKED_RATINGS_CHANGED);
+    intentFilter.addAction(TvInputManager
+      .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
+    registerReceiver(mBroadcastReceiver, intentFilter);
+}
+</pre>
+
+<p> See <a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> for more information about working with blocked content and providing
+parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that
+you may want to handle in your TV input service.</p>
+
+<p>The {@link android.media.tv.TvInputService} creates a
+{@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
+to handle player state changes. With {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
+the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
+video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
+for more information about working with {@link android.view.Surface} to render video.</p>
+
+<p>The {@link android.media.tv.TvInputService.Session} handles the
+{@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
+event when the user selects a channel, and notifies the system TV app for changes in the content and
+content meta data. These <code>notify()</code>code> methods are described in
+<a href="{@docRoot}training/tv/tif/ui.html#control">
+Control Content</a> and <a href="training/tv/tif/ui.html#track">Handle Track Selection</a> further
+in this training.</p>
+
+<h2 id="setup">Define Setup and Settings Activities</h2>
+
+<p>The system TV app works with the setup and settings activities you define for your TV input. The
+setup activity is required and must provide at least one channel record for the system database. The
+system TV app will invoke the setup activity when it cannot find a channel for the TV input.
+<p>The setup activity describes to the system TV app the channels made available through the TV
+input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
+and Updating Channel Data</a>.</p>
+
+<p>The settings activity is optional. You can define a settings activity to turn on parental
+controls, enable closed captions, set the display attributes, and so forth.</p>
+
+
diff --git a/docs/html/training/tv/tif/ui.jd b/docs/html/training/tv/tif/ui.jd
new file mode 100644
index 0000000..6ead3db
--- /dev/null
+++ b/docs/html/training/tv/tif/ui.jd
@@ -0,0 +1,304 @@
+page.title=Managing User Interaction
+page.tags=tv, tif
+helpoutsWidget=true
+
+trainingnavtop=true
+
+@jd:body
+
+<div id="tb-wrapper">
+<div id="tb">
+  <h2>This lesson teaches you to</h2>
+  <ol>
+    <li><a href="#surface">Integrate Player with Surface</a></li>
+    <li><a href="#overlay">Use an Overlay</a></li>
+    <li><a href="#control">Control Content</a></li>
+    <li><a href="#track">Handle Track Selection</a></li>
+  </ol>
+  <h2>Try It Out</h2>
+  <ul>
+    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
+      TV Input Service sample app</a></li>
+  </ul>
+</div>
+</div>
+
+<p>In the live TV experience the user changes channels and is presented with
+channel and program information briefly before the information disappears. Other types of information,
+such as messages ("DO NOT ATTEMPT AT HOME"), subtitles, or ads may need to persist. As with any TV
+app, such information should not interfere with the program content playing on the screen.</p>
+
+<img src="{@docRoot}images/tv/do-not-attempt.png" id="figure1">
+<p class="img-caption">
+  <strong>Figure 1.</strong> An overlay message in a live TV app.
+</p>
+
+<p>Also consider whether certain program content should be presented, given the
+content's rating and parental control settings, and how your app behaves and informs the user when
+content is blocked or unavailable. This lesson describes how to develop your TV input's user
+experience for these considerations.</p>
+
+<h2 id="surface">Integrate Player with Surface</h2>
+
+<p>Your TV input must render video onto a {@link android.view.Surface} object, which is passed by
+the {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) TvInputService.Session.onSetSurface()}
+method. Here's an example of how to use a {@link android.media.MediaPlayer} instance for playing
+content in the {@link android.view.Surface} object:</p>
+
+<pre>
+&#64;Override
+public boolean onSetSurface(Surface surface) {
+    if (mPlayer != null) {
+        mPlayer.setSurface(surface);
+    }
+    mSurface = surface;
+    return true;
+}
+
+&#64;Override
+public void onSetStreamVolume(float volume) {
+    if (mPlayer != null) {
+        mPlayer.setVolume(volume, volume);
+    }
+    mVolume = volume;
+}
+</pre>
+
+<p>Similarly, here's how to do it using <a href="{@docRoot}guide/topics/media/exoplayer.html">
+ExoPlayer</a>:</p>
+
+<pre>
+&#64;Override
+public boolean onSetSurface(Surface surface) {
+    if (mPlayer != null) {
+        mPlayer.sendMessage(mVideoRenderer,
+                MediaCodecVideoTrackRenderer.MSG_SET_SURFACE,
+                surface);
+    }
+    mSurface = surface;
+    return true;
+}
+
+&#64;Override
+public void onSetStreamVolume(float volume) {
+    if (mPlayer != null) {
+        mPlayer.sendMessage(mAudioRenderer,
+                MediaCodecAudioTrackRenderer.MSG_SET_VOLUME,
+                volume);
+    }
+    mVolume = volume;
+}
+</pre>
+
+<h2 id="overlay">Use an Overlay</h2>
+
+<p>Use an overlay to display subtitles, messages, ads or MHEG-5 data broadcasts. By default, the
+overlay is disabled. You can enable it when you create the session by calling
+{@link android.media.tv.TvInputService.Session#setOverlayViewEnabled(boolean) TvInputService.Session.setOverlayViewEnabled(true)},
+as in the following example:</p>
+
+<pre>
+&#64;Override
+public final Session onCreateSession(String inputId) {
+    BaseTvInputSessionImpl session = onCreateSessionInternal(inputId);
+    session.setOverlayViewEnabled(true);
+    mSessions.add(session);
+    return session;
+}
+</pre>
+
+<p>Use a {@link android.view.View} object for the overlay, returned from {@link android.media.tv.TvInputService.Session#onCreateOverlayView() TvInputService.Session.onCreateOverlayView()}, as shown here:</p>
+
+<pre>
+&#64;Override
+public View onCreateOverlayView() {
+    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+    View view = inflater.inflate(R.layout.overlayview, null);
+    mSubtitleView = (SubtitleView) view.findViewById(R.id.subtitles);
+
+    // Configure the subtitle view.
+    CaptionStyleCompat captionStyle;
+    float captionTextSize = getCaptionFontSize();
+    captionStyle = CaptionStyleCompat.createFromCaptionStyle(
+            mCaptioningManager.getUserStyle());
+    captionTextSize *= mCaptioningManager.getFontScale();
+    mSubtitleView.setStyle(captionStyle);
+    mSubtitleView.setTextSize(captionTextSize);
+    return view;
+}
+</pre>
+
+<p>The layout definition for the overlay might look something like this:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"&gt;
+
+    &lt;com.google.android.exoplayer.text.SubtitleView
+        android:id="@+id/subtitles"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom|center_horizontal"
+        android:layout_marginLeft="16dp"
+        android:layout_marginRight="16dp"
+        android:layout_marginBottom="32dp"
+        android:visibility="invisible"/&gt;
+&lt;/FrameLayout&gt;
+</pre>
+
+<h2 id="control">Control Content</h2>
+
+<p>When the user selects a channel, your TV input handles the {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri)
+onTune()} callback in the {@link android.media.tv.TvInputService.Session} object. The system TV
+app's parental controls determine what content displays, given the content rating.
+The following sections describe how to manage channel and program selection using the
+{@link android.media.tv.TvInputService.Session} <code>notify</code> methods that
+communicate with the system TV app.</p>
+
+<h3 id="unavailable">Make Video Unavailable</h3>
+
+<p>When the user changes the channel, you want to make sure the screen doesn't display any stray
+video artifacts before your TV input renders the content. When you call {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) TvInputService.Session.onTune()},
+you can prevent the video from being presented by calling {@link android.media.tv.TvInputService.Session#notifyVideoUnavailable(int) TvInputService.Session.notifyVideoUnavailable()}
+and passing the {@link android.media.tv.TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING} constant, as
+shown in the following example.</p>
+
+<pre>
+&#64;Override
+public boolean onTune(Uri channelUri) {
+    if (mSubtitleView != null) {
+        mSubtitleView.setVisibility(View.INVISIBLE);
+    }
+    notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+    mUnblockedRatingSet.clear();
+
+    mDbHandler.removeCallbacks(mPlayCurrentProgramRunnable);
+    mPlayCurrentProgramRunnable = new PlayCurrentProgramRunnable(channelUri);
+    mDbHandler.post(mPlayCurrentProgramRunnable);
+    return true;
+}
+</pre>
+
+<p>Then, when the content is rendered to the {@link android.view.Surface}, you call
+{@link android.media.tv.TvInputService.Session#notifyVideoAvailable() TvInputService.Session.notifyVideoAvailable()}
+to allow the video to display, like so:</p>
+
+<pre>
+&#64;Override
+public void onDrawnToSurface(Surface surface) {
+    mFirstFrameDrawn = true;
+    notifyVideoAvailable();
+}
+</pre>
+
+<p>This transition lasts only for fractions of a second, but presenting a blank screen is
+visually better than allowing the picture to flash odd blips and jitters.</p>
+
+<p>See also, <a href="#surface">Integrate Player with Surface</a> for more information about working
+with {@link android.view.Surface} to render video.</p>
+
+<h3 id="parental">Provide Parental Control</h3>
+
+<p>To determine if a given content is blocked by parental controls and content rating, you check the
+{@link android.media.tv.TvInputManager} class methods, {@link android.media.tv.TvInputManager#isParentalControlsEnabled()}
+and {@link android.media.tv.TvInputManager#isRatingBlocked(android.media.tv.TvContentRating)}. You
+might also want to make sure the content's {@link android.media.tv.TvContentRating} is included in a
+set of currently allowed content ratings. These considerations are shown in the following sample.</p>
+
+<pre>
+private void checkContentBlockNeeded() {
+    if (mCurrentContentRating == null || !mTvInputManager.isParentalControlsEnabled()
+            || !mTvInputManager.isRatingBlocked(mCurrentContentRating)
+            || mUnblockedRatingSet.contains(mCurrentContentRating)) {
+        // Content rating is changed so we don't need to block anymore.
+        // Unblock content here explicitly to resume playback.
+        unblockContent(null);
+        return;
+    }
+
+    mLastBlockedRating = mCurrentContentRating;
+    if (mPlayer != null) {
+        // Children restricted content might be blocked by TV app as well,
+        // but TIF should do its best not to show any single frame of blocked content.
+        releasePlayer();
+    }
+
+    notifyContentBlocked(mCurrentContentRating);
+}
+</pre>
+
+<p>Once you have determined if the content should or should not be blocked, notify the system TV
+app by calling the
+{@link android.media.tv.TvInputService.Session} method {@link android.media.tv.TvInputService.Session#notifyContentAllowed() notifyContentAllowed()}
+or
+{@link android.media.tv.TvInputService.Session#notifyContentBlocked(android.media.tv.TvContentRating) notifyContentBlocked()}
+, as shown in the previous example.</p>
+
+<p>Use the {@link android.media.tv.TvContentRating} class to generate the system-defined string for
+the {@link android.media.tv.TvContract.Programs#COLUMN_CONTENT_RATING} with the
+<code><a href="{@docRoot}reference/android/media/tv/TvContentRating.html#createRating(java.lang.String, java.lang.String, java.lang.String, java.lang.String...)">TvContentRating.createRating()</a></code>
+method, as shown here:</p>
+
+<pre>
+TvContentRating rating = TvContentRating.createRating(
+    "com.android.tv",
+    "US_TV",
+    "US_TV_PG",
+    "US_TV_D", "US_TV_L");
+</pre>
+
+<h2 id="track">Handle Track Selection</h2>
+
+<p>The {@link android.media.tv.TvTrackInfo} class holds information about media tracks such
+as the track type (video, audio, or subtitle) and so forth. </p>
+
+<p>The first time your TV input session is able to get track information, it should call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">TvInputService.Session.notifyTracksChanged()</a></code> with a list of all tracks to update the system TV app.  When there
+is a change in track information, call
+<code><a href="{@docRoot}reference/android/media/tv/TvInputService.Session.html#notifyTracksChanged(java.util.List<android.media.tv.TvTrackInfo>)">notifyTracksChanged()</a></code>
+again to update the system.
+
+</p>
+
+<p>The system TV app provides an interface for the user to select a specific track if more than one
+track is available for a given track type; for example, subtitles in different languages. Your TV
+input responds to the
+{@link android.media.tv.TvInputService.Session#onSelectTrack(int, java.lang.String) onSelectTrack()}
+call from the system TV app by calling
+{@link android.media.tv.TvInputService.Session#notifyTrackSelected(int, java.lang.String) notifyTrackSelected()}
+, as shown in the following example. Note that when <code>null</code>
+is passed as the track ID, this <em>deselects</em> the track.</p>
+
+<pre>
+&#64;Override
+public boolean onSelectTrack(int type, String trackId) {
+    if (mPlayer != null) {
+        if (type == TvTrackInfo.TYPE_SUBTITLE) {
+            if (!mCaptionEnabled && trackId != null) {
+                return false;
+            }
+            mSelectedSubtitleTrackId = trackId;
+            if (trackId == null) {
+                mSubtitleView.setVisibility(View.INVISIBLE);
+            }
+        }
+        if (mPlayer.selectTrack(type, trackId)) {
+            notifyTrackSelected(type, trackId);
+            return true;
+        }
+    }
+    return false;
+}
+</pre>
+
+
+
+
+
+
+
diff --git a/docs/html/training/wearables/apps/voice.jd b/docs/html/training/wearables/apps/voice.jd
index 6d49319..3aef3c4 100644
--- a/docs/html/training/wearables/apps/voice.jd
+++ b/docs/html/training/wearables/apps/voice.jd
@@ -131,6 +131,17 @@
   </tr>
 
   <tr>
+    <td>Start stopwatch</td>
+    <td>"Ok Google, start stopwatch"</td>
+    <td>
+      <dl>
+        <dt>Action</dt>
+        <dd><code>com.google.android.wearable.action.STOPWATCH</code></dd>
+      </dl>
+   </td>
+  </tr>
+
+  <tr>
     <td>Start/Stop a bike ride</td>
     <td>"OK Google, start cycling"<br/><br/>"OK Google, start my bike ride"<br/><br/>"OK Google, stop cycling"</td>
     <td>
diff --git a/docs/html/training/wearables/watch-faces/drawing.jd b/docs/html/training/wearables/watch-faces/drawing.jd
index 3c5da34..60da5d5 100644
--- a/docs/html/training/wearables/watch-faces/drawing.jd
+++ b/docs/html/training/wearables/watch-faces/drawing.jd
@@ -377,7 +377,8 @@
 
 <ul>
 <li>For devices that use low-bit ambient mode, the screen supports fewer bits for each color
-in ambient mode, so you should disable anti-aliasing.</li>
+in ambient mode, so you should disable anti-aliasing and bitmap filtering when the device switches
+to ambient mode.</li>
 <li>For devices that require burn-in protection, avoid using large blocks of white pixels in
 ambient mode and do not place content within 10 pixels of the edge of the screen, since the
 system shifts the content periodically to avoid pixel burn-in.</li>
@@ -385,7 +386,9 @@
 
 <p>For more information about low-bit ambient mode and burn-in protection, see
 <a href="{@docRoot}design/wear/watchfaces.html#SpecialScreens">Optimize for Special
-Screens</a>.</p>
+Screens</a>. For more information on how to disable bitmap filtering, see
+<a href="{@docRoot}training/wearables/watch-faces/performance.html#BitmapFiltering">Bitmap
+Filtering</a>.</p>
 
 
 <h2 id="Modes">Respond to Changes Between Modes</h2>
diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd
index 68438fe..118bc6a 100644
--- a/docs/html/training/wearables/watch-faces/performance.jd
+++ b/docs/html/training/wearables/watch-faces/performance.jd
@@ -99,7 +99,9 @@
 setFilterBitmap()} method. <a href="#fig2">Figure 2</a> shows a magnified view of a clock hand with
 and without bitmap filtering.</p>
 
-
+<p class="note"><strong>Note:</strong> In low-bit ambient mode, the system does not reliably
+render the colors in the image for bitmap filtering to process successfully. When ambient mode is
+active, disable bitmap filtering.</p>
 
 <h2 id="OutDrawing">Move Expensive Operations Outside the Drawing Method</h2>
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 150f195..48afcbf 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -45,6 +45,8 @@
  * Canvas and Drawables</a> developer guide.</p></div>
  */
 public class Canvas {
+    /** @hide */
+    public static boolean sCompatibilityRestore = false;
 
     /**
      * Should only be assigned in constructors (or setBitmap if software canvas),
@@ -557,7 +559,8 @@
      * an error to call restore() more times than save() was called.
      */
     public void restore() {
-        native_restore(mNativeCanvasWrapper);
+        boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated();
+        native_restore(mNativeCanvasWrapper, throwOnUnderflow);
     }
 
     /**
@@ -582,7 +585,8 @@
      * @param saveCount The save level to restore to.
      */
     public void restoreToCount(int saveCount) {
-        native_restoreToCount(mNativeCanvasWrapper, saveCount);
+        boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated();
+        native_restoreToCount(mNativeCanvasWrapper, saveCount, throwOnUnderflow);
     }
 
     /**
@@ -1988,9 +1992,10 @@
     private static native int native_saveLayerAlpha(long nativeCanvas, float l,
                                                     float t, float r, float b,
                                                     int alpha, int layerFlags);
-    private static native void native_restore(long canvasHandle);
+    private static native void native_restore(long canvasHandle, boolean tolerateUnderflow);
     private static native void native_restoreToCount(long canvasHandle,
-                                                     int saveCount);
+                                                     int saveCount,
+                                                     boolean tolerateUnderflow);
     private static native int native_getSaveCount(long canvasHandle);
 
     private static native void native_translate(long canvasHandle,
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1da198c..cd5f59d 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -2120,9 +2120,9 @@
         int contextLen = contextEnd - contextStart;
         char[] buf = TemporaryBuffer.obtain(contextLen);
         TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
-        int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
+        int relPos = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
         TemporaryBuffer.recycle(buf);
-        return result;
+        return (relPos == -1) ? -1 : relPos + contextStart;
     }
 
     /**
@@ -2249,6 +2249,26 @@
             bounds);
     }
 
+    /**
+     * Determine whether the typeface set on the paint has a glyph supporting the string. The
+     * simplest case is when the string contains a single character, in which this method
+     * determines whether the font has the character. In the case of multiple characters, the
+     * method returns true if there is a single glyph representing the ligature. For example, if
+     * the input is a pair of regional indicator symbols, determine whether there is an emoji flag
+     * for the pair.
+     *
+     * Finally, if the string contains a variation selector, the method only returns true if
+     * the fonts contains a glyph specific to that variation.
+     *
+     * Checking is done on the entire fallback chain, not just the immediate font referenced.
+     *
+     * @param string the string to test whether there is glyph support
+     * @return true if the typeface has a glyph for the string
+     */
+    public boolean hasGlyph(String string) {
+        return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string);
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -2334,4 +2354,6 @@
                                                              String settings);
     private static native int native_getHyphenEdit(long native_object);
     private static native void native_setHyphenEdit(long native_object, int hyphen);
+    private static native boolean native_hasGlyph(long native_object, long native_typeface,
+            int bidiFlags, String string);
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index a56e87e..28c26ff 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -173,7 +173,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations() | mAnimatedVectorState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mAnimatedVectorState.getChangingConfigurations();
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index dc10a81..6fe6b56 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -454,7 +454,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mBitmapState.getChangingConfigurations();
     }
 
     private boolean needMirroring() {
@@ -834,7 +834,7 @@
 
         // Apply theme to contained color state list.
         if (state.mTint != null && state.mTint.canApplyTheme()) {
-            state.mTint.applyTheme(t);
+            state.mTint = state.mTint.obtainForTheme(t);
         }
 
         // Update local properties.
@@ -882,7 +882,7 @@
 
     @Override
     public final ConstantState getConstantState() {
-        mBitmapState.mChangingConfigurations = getChangingConfigurations();
+        mBitmapState.mChangingConfigurations |= getChangingConfigurations();
         return mBitmapState;
     }
 
@@ -950,7 +950,8 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index f75ab36..8e91621 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -276,7 +276,7 @@
         }
 
         if (state.mTint != null && state.mTint.canApplyTheme()) {
-            state.mTint.applyTheme(t);
+            state.mTint = state.mTint.obtainForTheme(t);
         }
 
         updateLocalState(t.getResources());
@@ -327,7 +327,8 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 56876e94..e8b8c77 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -816,9 +816,12 @@
      * returned.  You can use the method {@link #resolveOpacity} to perform a
      * standard reduction of two opacities to the appropriate single output.
      *
-     * <p>Note that the returned value does <em>not</em> take into account a
+     * <p>Note that the returned value does not necessarily take into account a
      * custom alpha or color filter that has been applied by the client through
-     * the {@link #setAlpha} or {@link #setColorFilter} methods.
+     * the {@link #setAlpha} or {@link #setColorFilter} methods. Some subclasses,
+     * such as {@link BitmapDrawable}, {@link ColorDrawable}, and {@link GradientDrawable},
+     * do account for the value of {@link #setAlpha}, but the general behavior is dependent
+     * upon the implementation of the subclass.
      *
      * @return int The opacity class of the Drawable.
      *
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index ddcb48b..b03fe3a 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -87,8 +87,7 @@
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
-                | mDrawableContainerState.mChangingConfigurations
-                | mDrawableContainerState.mChildrenChangingConfigurations;
+                | mDrawableContainerState.getChangingConfigurations();
     }
 
     private boolean needsMirroring() {
@@ -865,6 +864,9 @@
                 for (int i = 0; i < N; i++) {
                     if (drawables[i] != null && drawables[i].canApplyTheme()) {
                         drawables[i].applyTheme(theme);
+
+                        // Update cached mask of child changing configurations.
+                        mChildrenChangingConfigurations |= drawables[i].getChangingConfigurations();
                     }
                 }
             }
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 1d6c60f..0da4275 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -180,8 +180,7 @@
     @Override
     public int getChangingConfigurations() {
         return super.getChangingConfigurations()
-                | (mState != null ? mState.mChangingConfigurations : 0)
-                | mDrawable.getChangingConfigurations();
+                | (mState != null ? mState.getChangingConfigurations() : 0);
     }
 
     @Override
@@ -433,7 +432,7 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations | mDrawableState.getChangingConfigurations();
         }
 
         public boolean canConstantState() {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index eff152c..4c2817c 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -491,19 +491,21 @@
     }
 
     /**
-     * <p>Sets the colors used to draw the gradient. Each color is specified as an
-     * ARGB integer and the array must contain at least 2 colors.</p>
-     * <p><strong>Note</strong>: changing colors will affect all instances
-     * of a drawable loaded from a resource. It is recommended to invoke
-     * {@link #mutate()} before changing the colors.</p>
+     * Sets the colors used to draw the gradient.
+     * <p>
+     * Each color is specified as an ARGB integer and the array must contain at
+     * least 2 colors.
+     * <p>
+     * <strong>Note</strong>: changing colors will affect all instances of a
+     * drawable loaded from a resource. It is recommended to invoke
+     * {@link #mutate()} before changing the colors.
      *
-     * @param colors 2 or more ARGB colors
-     *
+     * @param colors an array containing 2 or more ARGB colors
      * @see #mutate()
      * @see #setColor(int)
      */
     public void setColors(@ColorInt int[] colors) {
-        mGradientState.setColors(colors);
+        mGradientState.setGradientColors(colors);
         mGradientIsDirty = true;
         invalidateSelf();
     }
@@ -568,7 +570,7 @@
             mFillPaint.setAlpha(currFillAlpha);
             mFillPaint.setDither(st.mDither);
             mFillPaint.setColorFilter(colorFilter);
-            if (colorFilter != null && st.mColorStateList == null) {
+            if (colorFilter != null && st.mSolidColors == null) {
                 mFillPaint.setColor(mAlpha << 24);
             }
             if (haveStroke) {
@@ -715,7 +717,7 @@
      * @see #setColors(int[])
      */
     public void setColor(@ColorInt int argb) {
-        mGradientState.setColorStateList(ColorStateList.valueOf(argb));
+        mGradientState.setSolidColors(ColorStateList.valueOf(argb));
         mFillPaint.setColor(argb);
         invalidateSelf();
     }
@@ -734,7 +736,7 @@
      * @see #mutate()
      */
     public void setColor(ColorStateList colorStateList) {
-        mGradientState.setColorStateList(colorStateList);
+        mGradientState.setSolidColors(colorStateList);
         final int color;
         if (colorStateList == null) {
             color = Color.TRANSPARENT;
@@ -751,9 +753,9 @@
         boolean invalidateSelf = false;
 
         final GradientState s = mGradientState;
-        final ColorStateList stateList = s.mColorStateList;
-        if (stateList != null) {
-            final int newColor = stateList.getColorForState(stateSet, 0);
+        final ColorStateList solidColors = s.mSolidColors;
+        if (solidColors != null) {
+            final int newColor = solidColors.getColorForState(stateSet, 0);
             final int oldColor = mFillPaint.getColor();
             if (oldColor != newColor) {
                 mFillPaint.setColor(newColor);
@@ -763,12 +765,12 @@
 
         final Paint strokePaint = mStrokePaint;
         if (strokePaint != null) {
-            final ColorStateList strokeStateList = s.mStrokeColorStateList;
-            if (strokeStateList != null) {
-                final int newStrokeColor = strokeStateList.getColorForState(stateSet, 0);
-                final int oldStrokeColor = strokePaint.getColor();
-                if (oldStrokeColor != newStrokeColor) {
-                    strokePaint.setColor(newStrokeColor);
+            final ColorStateList strokeColors = s.mStrokeColors;
+            if (strokeColors != null) {
+                final int newColor = strokeColors.getColorForState(stateSet, 0);
+                final int oldColor = strokePaint.getColor();
+                if (oldColor != newColor) {
+                    strokePaint.setColor(newColor);
                     invalidateSelf = true;
                 }
             }
@@ -791,14 +793,14 @@
     public boolean isStateful() {
         final GradientState s = mGradientState;
         return super.isStateful()
-                || (s.mColorStateList != null && s.mColorStateList.isStateful())
-                || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful())
+                || (s.mSolidColors != null && s.mSolidColors.isStateful())
+                || (s.mStrokeColors != null && s.mStrokeColors.isStateful())
                 || (s.mTint != null && s.mTint.isStateful());
     }
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations() | mGradientState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mGradientState.getChangingConfigurations();
     }
 
     @Override
@@ -899,10 +901,10 @@
             mRect.set(bounds.left + inset, bounds.top + inset,
                       bounds.right - inset, bounds.bottom - inset);
 
-            final int[] colors = st.mColors;
-            if (colors != null) {
-                RectF r = mRect;
-                float x0, x1, y0, y1;
+            final int[] gradientColors = st.mGradientColors;
+            if (gradientColors != null) {
+                final RectF r = mRect;
+                final float x0, x1, y0, y1;
 
                 if (st.mGradient == LINEAR_GRADIENT) {
                     final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
@@ -942,7 +944,7 @@
                     }
 
                     mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1,
-                            colors, st.mPositions, Shader.TileMode.CLAMP));
+                            gradientColors, st.mPositions, Shader.TileMode.CLAMP));
                 } else if (st.mGradient == RADIAL_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
@@ -971,22 +973,22 @@
                     }
 
                     mFillPaint.setShader(new RadialGradient(
-                            x0, y0, radius, colors, null, Shader.TileMode.CLAMP));
+                            x0, y0, radius, gradientColors, null, Shader.TileMode.CLAMP));
                 } else if (st.mGradient == SWEEP_GRADIENT) {
                     x0 = r.left + (r.right - r.left) * st.mCenterX;
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
 
-                    int[] tempColors = colors;
+                    int[] tempColors = gradientColors;
                     float[] tempPositions = null;
 
                     if (st.mUseLevel) {
                         tempColors = st.mTempColors;
-                        final int length = colors.length;
+                        final int length = gradientColors.length;
                         if (tempColors == null || tempColors.length != length + 1) {
                             tempColors = st.mTempColors = new int[length + 1];
                         }
-                        System.arraycopy(colors, 0, tempColors, 0, length);
-                        tempColors[length] = colors[length - 1];
+                        System.arraycopy(gradientColors, 0, tempColors, 0, length);
+                        tempColors[length] = gradientColors[length - 1];
 
                         tempPositions = st.mTempPositions;
                         final float fraction = 1.0f / (length - 1);
@@ -1006,7 +1008,7 @@
 
                 // If we don't have a solid color, the alpha channel must be
                 // maxed out so that alpha modulation works correctly.
-                if (st.mColorStateList == null) {
+                if (st.mSolidColors == null) {
                     mFillPaint.setColor(Color.BLACK);
                 }
             }
@@ -1044,15 +1046,15 @@
         }
 
         if (state.mTint != null && state.mTint.canApplyTheme()) {
-            state.mTint.applyTheme(t);
+            state.mTint = state.mTint.obtainForTheme(t);
         }
 
-        if (state.mColorStateList != null && state.mColorStateList.canApplyTheme()) {
-            state.mColorStateList.applyTheme(t);
+        if (state.mSolidColors != null && state.mSolidColors.canApplyTheme()) {
+            state.mSolidColors = state.mSolidColors.obtainForTheme(t);
         }
 
-        if (state.mStrokeColorStateList != null && state.mStrokeColorStateList.canApplyTheme()) {
-            state.mStrokeColorStateList.applyTheme(t);
+        if (state.mStrokeColors != null && state.mStrokeColors.canApplyTheme()) {
+            state.mStrokeColors = state.mStrokeColors.obtainForTheme(t);
         }
 
         applyThemeChildElements(t);
@@ -1288,7 +1290,7 @@
         ColorStateList colorStateList = a.getColorStateList(
                 R.styleable.GradientDrawableStroke_color);
         if (colorStateList == null) {
-            colorStateList = st.mStrokeColorStateList;
+            colorStateList = st.mStrokeColors;
         }
 
         if (dashWidth != 0.0f) {
@@ -1346,10 +1348,10 @@
                 R.styleable.GradientDrawableGradient_endColor, 0);
 
         if (hasCenterColor) {
-            st.mColors = new int[3];
-            st.mColors[0] = startColor;
-            st.mColors[1] = centerColor;
-            st.mColors[2] = endColor;
+            st.mGradientColors = new int[3];
+            st.mGradientColors[0] = startColor;
+            st.mGradientColors[1] = centerColor;
+            st.mGradientColors[2] = endColor;
 
             st.mPositions = new float[3];
             st.mPositions[0] = 0.0f;
@@ -1357,9 +1359,9 @@
             st.mPositions[1] = st.mCenterX != 0.5f ? st.mCenterX : st.mCenterY;
             st.mPositions[2] = 1f;
         } else {
-            st.mColors = new int[2];
-            st.mColors[0] = startColor;
-            st.mColors[1] = endColor;
+            st.mGradientColors = new int[2];
+            st.mGradientColors[0] = startColor;
+            st.mGradientColors[1] = endColor;
         }
 
         if (st.mGradient == LINEAR_GRADIENT) {
@@ -1552,9 +1554,9 @@
         public int mGradient = LINEAR_GRADIENT;
         public int mAngle = 0;
         public Orientation mOrientation;
-        public ColorStateList mColorStateList;
-        public ColorStateList mStrokeColorStateList;
-        public int[] mColors;
+        public ColorStateList mSolidColors;
+        public ColorStateList mStrokeColors;
+        public int[] mGradientColors;
         public int[] mTempColors; // no need to copy
         public float[] mTempPositions; // no need to copy
         public float[] mPositions;
@@ -1593,9 +1595,9 @@
         int[] mAttrCorners;
         int[] mAttrPadding;
 
-        public GradientState(Orientation orientation, int[] colors) {
+        public GradientState(Orientation orientation, int[] gradientColors) {
             mOrientation = orientation;
-            setColors(colors);
+            setGradientColors(gradientColors);
         }
 
         public GradientState(GradientState state) {
@@ -1604,14 +1606,14 @@
             mGradient = state.mGradient;
             mAngle = state.mAngle;
             mOrientation = state.mOrientation;
-            mColorStateList = state.mColorStateList;
-            if (state.mColors != null) {
-                mColors = state.mColors.clone();
+            mSolidColors = state.mSolidColors;
+            if (state.mGradientColors != null) {
+                mGradientColors = state.mGradientColors.clone();
             }
             if (state.mPositions != null) {
                 mPositions = state.mPositions.clone();
             }
-            mStrokeColorStateList = state.mStrokeColorStateList;
+            mStrokeColors = state.mStrokeColors;
             mStrokeWidth = state.mStrokeWidth;
             mStrokeDashWidth = state.mStrokeDashWidth;
             mStrokeDashGap = state.mStrokeDashGap;
@@ -1655,8 +1657,8 @@
                     || mAttrSolid != null || mAttrStroke != null
                     || mAttrCorners != null || mAttrPadding != null
                     || (mTint != null && mTint.canApplyTheme())
-                    || (mStrokeColorStateList != null && mStrokeColorStateList.canApplyTheme())
-                    || (mColorStateList != null && mColorStateList.canApplyTheme())
+                    || (mStrokeColors != null && mStrokeColors.canApplyTheme())
+                    || (mSolidColors != null && mSolidColors.canApplyTheme())
                     || super.canApplyTheme();
         }
 
@@ -1672,7 +1674,10 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | (mStrokeColors != null ? mStrokeColors.getChangingConfigurations() : 0)
+                    | (mSolidColors != null ? mSolidColors.getChangingConfigurations() : 0)
+                    | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
 
         public void setShape(int shape) {
@@ -1689,15 +1694,15 @@
             mCenterY = y;
         }
 
-        public void setColors(int[] colors) {
-            mColors = colors;
-            mColorStateList = null;
+        public void setGradientColors(int[] colors) {
+            mGradientColors = colors;
+            mSolidColors = null;
             computeOpacity();
         }
 
-        public void setColorStateList(ColorStateList colorStateList) {
-            mColors = null;
-            mColorStateList = colorStateList;
+        public void setSolidColors(ColorStateList colors) {
+            mGradientColors = null;
+            mSolidColors = colors;
             computeOpacity();
         }
 
@@ -1705,16 +1710,16 @@
             mOpaqueOverBounds = false;
             mOpaqueOverShape = false;
 
-            if (mColors != null) {
-                for (int i = 0; i < mColors.length; i++) {
-                    if (!isOpaque(mColors[i])) {
+            if (mGradientColors != null) {
+                for (int i = 0; i < mGradientColors.length; i++) {
+                    if (!isOpaque(mGradientColors[i])) {
                         return;
                     }
                 }
             }
 
             // An unfilled shape is not opaque over bounds or shape
-            if (mColors == null && mColorStateList == null) {
+            if (mGradientColors == null && mSolidColors == null) {
                 return;
             }
 
@@ -1726,10 +1731,9 @@
                     && mRadiusArray == null;
         }
 
-        public void setStroke(
-                int width, ColorStateList colorStateList, float dashWidth, float dashGap) {
+        public void setStroke(int width, ColorStateList colors, float dashWidth, float dashGap) {
             mStrokeWidth = width;
-            mStrokeColorStateList = colorStateList;
+            mStrokeColors = colors;
             mStrokeDashWidth = dashWidth;
             mStrokeDashGap = dashGap;
             computeOpacity();
@@ -1781,11 +1785,11 @@
     private void updateLocalState(Resources res) {
         final GradientState state = mGradientState;
 
-        if (state.mColorStateList != null) {
+        if (state.mSolidColors != null) {
             final int[] currentState = getState();
-            final int stateColor = state.mColorStateList.getColorForState(currentState, 0);
+            final int stateColor = state.mSolidColors.getColorForState(currentState, 0);
             mFillPaint.setColor(stateColor);
-        } else if (state.mColors == null) {
+        } else if (state.mGradientColors == null) {
             // If we don't have a solid color and we don't have a gradient,
             // the app is stroking the shape, set the color to the default
             // value of state.mSolidColor
@@ -1802,9 +1806,9 @@
             mStrokePaint.setStyle(Paint.Style.STROKE);
             mStrokePaint.setStrokeWidth(state.mStrokeWidth);
 
-            if (state.mStrokeColorStateList != null) {
+            if (state.mStrokeColors != null) {
                 final int[] currentState = getState();
-                final int strokeStateColor = state.mStrokeColorStateList.getColorForState(
+                final int strokeStateColor = state.mStrokeColors.getColorForState(
                         currentState, 0);
                 mStrokePaint.setColor(strokeStateColor);
             }
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 97f7105..e1ebdbb 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -242,26 +242,12 @@
     }
 
     @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
-    @Override
     DrawableWrapperState mutateConstantState() {
         mState = new InsetState(mState);
         return mState;
     }
 
     static final class InsetState extends DrawableWrapper.DrawableWrapperState {
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
-
-        ConstantState mDrawableState;
-
         int mInsetLeft = 0;
         int mInsetTop = 0;
         int mInsetRight = 0;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 30fbe16..05a81de 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -163,7 +163,6 @@
         inflateLayers(r, parser, attrs, theme);
 
         ensurePadding();
-        onStateChange(getState());
     }
 
     /**
@@ -211,7 +210,11 @@
             updateLayerFromTypedArray(layer, a);
             a.recycle();
 
-            if (layer.mDrawable == null) {
+            // If the layer doesn't have a drawable or unresolved theme
+            // attribute for a drawable, attempt to parse one from the child
+            // element.
+            if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
+                    layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
                 while ((type = parser.next()) == XmlPullParser.TEXT) {
                 }
                 if (type != XmlPullParser.START_TAG) {
@@ -296,11 +299,13 @@
             final Drawable d = layer.mDrawable;
             if (d.canApplyTheme()) {
                 d.applyTheme(t);
+
+                // Update cached mask of child changing configurations.
+                state.mChildrenChangingConfigurations |= d.getChangingConfigurations();
             }
         }
 
         ensurePadding();
-        onStateChange(getState());
     }
 
     @Override
@@ -882,9 +887,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mLayerState.mChangingConfigurations
-                | mLayerState.mChildrenChangingConfigurations;
+        return super.getChangingConfigurations() | mLayerState.getChangingConfigurations();
     }
 
     @Override
@@ -1493,7 +1496,8 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | mChildrenChangingConfigurations;
         }
 
         public final int getOpacity() {
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 487162e..9bf33cf 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -266,7 +266,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mNinePatchState.getChangingConfigurations();
     }
 
     @Override
@@ -498,7 +498,7 @@
         }
 
         if (state.mTint != null && state.mTint.canApplyTheme()) {
-            state.mTint.applyTheme(t);
+            state.mTint = state.mTint.obtainForTheme(t);
         }
 
         updateLocalState(t.getResources());
@@ -680,7 +680,8 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 23f93fd..6731a17 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -479,7 +479,7 @@
         }
 
         if (state.mColor != null && state.mColor.canApplyTheme()) {
-            state.mColor.applyTheme(t);
+            state.mColor = state.mColor.obtainForTheme(t);
         }
 
         updateLocalState();
@@ -955,6 +955,12 @@
         public Drawable newDrawable(Resources res) {
             return new RippleDrawable(this, res);
         }
+
+        @Override
+        public int getChangingConfigurations() {
+            return super.getChangingConfigurations()
+                    | (mColor != null ? mColor.getChangingConfigurations() : 0);
+        }
     }
 
     private RippleDrawable(RippleState state, Resources res) {
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 15e16f1..036a078 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -89,9 +89,6 @@
 
         final RotateState state = mState;
 
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
         // Extract the theme attributes, if any.
         state.mThemeAttrs = a.extractThemeAttrs();
 
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index fc88c15..334b3bd 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -53,9 +53,9 @@
  * For more information about how to use ShapeDrawable, read the <a
  * href="{@docRoot}guide/topics/graphics/2d-graphics.html#shape-drawable">
  * Canvas and Drawables</a> document. For more information about defining a
- * ShapeDrawable in XML, read the <a href="{@docRoot}
- * guide/topics/resources/drawable-resource.html#Shape">Drawable Resources</a>
- * document.
+ * ShapeDrawable in XML, read the
+ * <a href="{@docRoot}guide/topics/resources/drawable-resource.html#Shape">
+ * Drawable Resources</a> document.
  * </p>
  * </div>
  *
@@ -261,8 +261,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mShapeState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mShapeState.getChangingConfigurations();
     }
 
     /**
@@ -427,7 +426,7 @@
 
         // Apply theme to contained color state list.
         if (state.mTint != null && state.mTint.canApplyTheme()) {
-            state.mTint.applyTheme(t);
+            state.mTint = state.mTint.obtainForTheme(t);
         }
 
         // Update local properties.
@@ -578,7 +577,8 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index b827682..f4df14e 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -36,6 +36,7 @@
 import android.util.AttributeSet;
 import android.util.LayoutDirection;
 import android.util.Log;
+import android.util.MathUtils;
 import android.util.PathParser;
 import android.util.Xml;
 
@@ -389,7 +390,7 @@
 
         // Apply theme to contained color state list.
         if (state.mTint != null && state.mTint.canApplyTheme()) {
-            state.mTint.applyTheme(t);
+            state.mTint = state.mTint.obtainForTheme(t);
         }
 
         final VPathRenderer path = state.mVPathRenderer;
@@ -625,7 +626,7 @@
 
     @Override
     public int getChangingConfigurations() {
-        return super.getChangingConfigurations() | mVectorState.mChangingConfigurations;
+        return super.getChangingConfigurations() | mVectorState.getChangingConfigurations();
     }
 
     void setAllowCaching(boolean allowCaching) {
@@ -784,7 +785,8 @@
 
         @Override
         public int getChangingConfigurations() {
-            return mChangingConfigurations;
+            return mChangingConfigurations
+                    | (mTint != null ? mTint.getChangingConfigurations() : 0);
         }
     }
 
@@ -955,10 +957,16 @@
             final float scaleX = w / mViewportWidth;
             final float scaleY = h / mViewportHeight;
             final float minScale = Math.min(scaleX, scaleY);
+            final Matrix groupStackedMatrix = vGroup.mStackedMatrix;
 
-            mFinalPathMatrix.set(vGroup.mStackedMatrix);
+            mFinalPathMatrix.set(groupStackedMatrix);
             mFinalPathMatrix.postScale(scaleX, scaleY);
 
+            final float matrixScale = getMatrixScale(groupStackedMatrix);
+            if (matrixScale == 0) {
+                // When either x or y is scaled to 0, we don't need to draw anything.
+                return;
+            }
             vPath.toPath(mPath);
             final Path path = mPath;
 
@@ -966,7 +974,7 @@
 
             if (vPath.isClipPath()) {
                 mRenderPath.addPath(path, mFinalPathMatrix);
-                canvas.clipPath(mRenderPath, Region.Op.REPLACE);
+                canvas.clipPath(mRenderPath);
             } else {
                 VFullPath fullPath = (VFullPath) vPath;
                 if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
@@ -1024,11 +1032,41 @@
                     strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
                     strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
                     strokePaint.setColorFilter(filter);
-                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale);
+                    final float finalStrokeScale = minScale * matrixScale;
+                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
                     canvas.drawPath(mRenderPath, strokePaint);
                 }
             }
         }
+
+        private float getMatrixScale(Matrix groupStackedMatrix) {
+            // Given unit vectors A = (0, 1) and B = (1, 0).
+            // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+            // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+            // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+            // If  max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+            //
+            // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+            // scale on x and y axis, and take the minimal of these two.
+            // For skew case, an unit square will mapped to a parallelogram. And this function will
+            // return the minimal height of the 2 bases.
+            float[] unitVectors = new float[] {0, 1, 1, 0};
+            groupStackedMatrix.mapVectors(unitVectors);
+            float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
+            float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
+            float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
+                    unitVectors[2], unitVectors[3]);
+            float maxScale = MathUtils.max(scaleX, scaleY);
+
+            float matrixScale = 0;
+            if (maxScale > 0) {
+                matrixScale = MathUtils.abs(crossProduct) / maxScale;
+            }
+            if (DBG_VECTOR_DRAWABLE) {
+                Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
+            }
+            return matrixScale;
+        }
     }
 
     private static class VGroup {
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 65160d5..da70e9b 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -112,7 +112,7 @@
  *
  * The PNG chunk type is "npTc".
  */
-struct Res_png_9patch
+struct alignas(uintptr_t) Res_png_9patch
 {
     Res_png_9patch() : wasDeserialized(false), xDivsOffset(0),
                        yDivsOffset(0), colorsOffset(0) { }
@@ -1333,7 +1333,11 @@
         FLAG_COMPLEX = 0x0001,
         // If set, this resource has been declared public, so libraries
         // are allowed to reference it.
-        FLAG_PUBLIC = 0x0002
+        FLAG_PUBLIC = 0x0002,
+        // If set, this is a weak resource and may be overriden by strong
+        // resources of the same name/type. This is only useful during
+        // linking with other resource tables.
+        FLAG_WEAK = 0x0004
     };
     uint16_t flags;
     
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 1d16ca1..c5b6a68 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -457,7 +457,7 @@
 
         String keyAlgorithmString = key.getAlgorithm();
         @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
-        @KeyStoreKeyConstraints.AlgorithmEnum Integer digest;
+        @KeyStoreKeyConstraints.DigestEnum Integer digest;
         try {
             keyAlgorithm =
                     KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString);
@@ -466,100 +466,109 @@
             throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
         }
 
-        if ((params.getAlgorithm() != null) && (params.getAlgorithm() != keyAlgorithm)) {
-            throw new KeyStoreException("Key algorithm mismatch. Key: " + keyAlgorithmString
-                    + ", parameter spec: "
-                    + KeyStoreKeyConstraints.Algorithm.toString(params.getAlgorithm()));
-        }
-
         KeymasterArguments args = new KeymasterArguments();
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
                 KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm));
 
-        if (digest != null) {
-            // Digest available from JCA key algorithm
-            if (params.getDigest() != null) {
-                // Digest also specified in parameters -- check that these two match
-                if (digest != params.getDigest()) {
-                    throw new KeyStoreException("Key digest mismatch. Key: " + keyAlgorithmString
+        @KeyStoreKeyConstraints.DigestEnum int digests;
+        if (params.isDigestsSpecified()) {
+            // Digest(s) specified in parameters
+            if (digest != null) {
+                // Digest also specified in the JCA key algorithm name.
+                if ((params.getDigests() & digest) != digest) {
+                    throw new KeyStoreException("Key digest mismatch"
+                            + ". Key: " + keyAlgorithmString
                             + ", parameter spec: "
-                            + KeyStoreKeyConstraints.Digest.toString(params.getDigest()));
+                            + KeyStoreKeyConstraints.Digest.allToString(params.getDigests()));
                 }
             }
+            digests = params.getDigests();
         } else {
-            // Digest not available from JCA key algorithm
-            digest = params.getDigest();
-        }
-        if (digest != null) {
-            args.addInt(KeymasterDefs.KM_TAG_DIGEST,
-                    KeyStoreKeyConstraints.Digest.toKeymaster(digest));
-        }
-        if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
-            if (digest == null) {
-                throw new IllegalStateException("Digest algorithm must be specified for key"
-                        + " algorithm " + keyAlgorithmString);
+            // No digest specified in parameters
+            if (digest != null) {
+                // Digest specified in the JCA key algorithm name.
+                digests = digest;
+            } else {
+                digests = 0;
             }
+        }
+        for (int keymasterDigest : KeyStoreKeyConstraints.Digest.allToKeymaster(digests)) {
+            args.addInt(KeymasterDefs.KM_TAG_DIGEST, keymasterDigest);
+        }
+        if (digests != 0) {
+            // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
+            // This code will blow up if mode than one digest is specified.
             Integer digestOutputSizeBytes =
                     KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
             if (digestOutputSizeBytes != null) {
-                // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
                 // TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
                 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
             }
         }
+        if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
+            if (digests == 0) {
+                throw new KeyStoreException("At least one digest algorithm must be specified"
+                        + " for key algorithm " + keyAlgorithmString);
+            }
+        }
 
-        @KeyStoreKeyConstraints.PurposeEnum int purposes = (params.getPurposes() != null)
-                ? params.getPurposes()
-                : (KeyStoreKeyConstraints.Purpose.ENCRYPT
-                        | KeyStoreKeyConstraints.Purpose.DECRYPT
-                        | KeyStoreKeyConstraints.Purpose.SIGN
-                        | KeyStoreKeyConstraints.Purpose.VERIFY);
-        for (int keymasterPurpose :
-            KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
+        @KeyStoreKeyConstraints.PurposeEnum int purposes = params.getPurposes();
+        @KeyStoreKeyConstraints.BlockModeEnum int blockModes = params.getBlockModes();
+        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+                && (params.isRandomizedEncryptionRequired())) {
+            @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
+                    blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
+            if (incompatibleBlockModes != 0) {
+                throw new KeyStoreException("Randomized encryption (IND-CPA) required but may be"
+                        + " violated by block mode(s): "
+                        + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
+                        + ". See KeyStoreParameter documentation.");
+            }
+        }
+        for (int keymasterPurpose : KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
-        if (params.getBlockMode() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE,
-                    KeyStoreKeyConstraints.BlockMode.toKeymaster(params.getBlockMode()));
+        for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
+            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
         }
-        if (params.getPadding() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING,
-                    KeyStoreKeyConstraints.Padding.toKeymaster(params.getPadding()));
+        for (int keymasterPadding :
+            KeyStoreKeyConstraints.Padding.allToKeymaster(params.getPaddings())) {
+            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
         }
-        if (params.getMaxUsesPerBoot() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT, params.getMaxUsesPerBoot());
-        }
-        if (params.getMinSecondsBetweenOperations() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS,
-                    params.getMinSecondsBetweenOperations());
-        }
-        if (params.getUserAuthenticators().isEmpty()) {
+        if (params.getUserAuthenticators() == 0) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
-        // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
-//            for (int userAuthenticatorId : params.getUserAuthenticators()) {
-//                args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
-//            }
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                            params.getUserAuthenticators()));
         }
-        if (params.getUserAuthenticationValidityDurationSeconds() != null) {
+        if (params.isInvalidatedOnNewFingerprintEnrolled()) {
+            // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+            // that.
+        }
+        if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
             args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
                     params.getUserAuthenticationValidityDurationSeconds());
         }
-        if (params.getKeyValidityStart() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, params.getKeyValidityStart());
-        }
-        if (params.getKeyValidityForOriginationEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                    params.getKeyValidityForOriginationEnd());
-        }
-        if (params.getKeyValidityForConsumptionEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                    params.getKeyValidityForConsumptionEnd());
-        }
+        args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+                (params.getKeyValidityStart() != null)
+                        ? params.getKeyValidityStart() : new Date(0));
+        args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+                (params.getKeyValidityForOriginationEnd() != null)
+                        ? params.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
+        args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+                (params.getKeyValidityForConsumptionEnd() != null)
+                        ? params.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
         // TODO: Remove this once keymaster does not require us to specify the size of imported key.
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
 
+        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+                && (!params.isRandomizedEncryptionRequired())) {
+            // Permit caller-provided IV when encrypting with this key
+            args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
+        }
+
         Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias);
         String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
         int errorCode = mKeyStore.importKey(
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index 7313c48..43f3b30 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -18,6 +18,9 @@
 
 import java.security.Provider;
 
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
 /**
  * A provider focused on providing JCA interfaces for the Android KeyStore.
  *
@@ -26,22 +29,105 @@
 public class AndroidKeyStoreProvider extends Provider {
     public static final String PROVIDER_NAME = "AndroidKeyStore";
 
+    // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
+    // classes when this provider is instantiated and installed early on during each app's
+    // initialization process.
+
+    private static final String PACKAGE_NAME = "android.security";
+    private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
+            PACKAGE_NAME + ".KeyStoreSecretKey";
+
     public AndroidKeyStoreProvider() {
         super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
 
         // java.security.KeyStore
-        put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
+        put("KeyStore.AndroidKeyStore", PACKAGE_NAME + ".AndroidKeyStore");
 
         // java.security.KeyPairGenerator
-        put("KeyPairGenerator.EC", AndroidKeyPairGenerator.EC.class.getName());
-        put("KeyPairGenerator.RSA", AndroidKeyPairGenerator.RSA.class.getName());
+        put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyPairGenerator$EC");
+        put("KeyPairGenerator.RSA", PACKAGE_NAME +  ".AndroidKeyPairGenerator$RSA");
 
         // javax.crypto.KeyGenerator
-        put("KeyGenerator.AES", KeyStoreKeyGeneratorSpi.AES.class.getName());
-        put("KeyGenerator.HmacSHA256", KeyStoreKeyGeneratorSpi.HmacSHA256.class.getName());
+        put("KeyGenerator.AES", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$AES");
+        put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA1");
+        put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA224");
+        put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA256");
+        put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA384");
+        put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA512");
+
+        // java.security.SecretKeyFactory
+        putSecretKeyFactoryImpl("AES");
+        putSecretKeyFactoryImpl("HmacSHA1");
+        putSecretKeyFactoryImpl("HmacSHA224");
+        putSecretKeyFactoryImpl("HmacSHA256");
+        putSecretKeyFactoryImpl("HmacSHA384");
+        putSecretKeyFactoryImpl("HmacSHA512");
 
         // javax.crypto.Mac
-        put("Mac.HmacSHA256", KeyStoreHmacSpi.HmacSHA256.class.getName());
-        put("Mac.HmacSHA256 SupportedKeyClasses", KeyStoreSecretKey.class.getName());
+        putMacImpl("HmacSHA1", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA1");
+        putMacImpl("HmacSHA224", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA224");
+        putMacImpl("HmacSHA256", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA256");
+        putMacImpl("HmacSHA384", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA384");
+        putMacImpl("HmacSHA512", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA512");
+
+        // javax.crypto.Cipher
+        putSymmetricCipherImpl("AES/ECB/NoPadding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$NoPadding");
+        putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$ECB$PKCS7Padding");
+
+        putSymmetricCipherImpl("AES/CBC/NoPadding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$NoPadding");
+        putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CBC$PKCS7Padding");
+
+        putSymmetricCipherImpl("AES/CTR/NoPadding",
+                PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CTR$NoPadding");
+    }
+
+    private void putSecretKeyFactoryImpl(String algorithm) {
+        put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".KeyStoreSecretKeyFactorySpi");
+    }
+
+    private void putMacImpl(String algorithm, String implClass) {
+        put("Mac." + algorithm, implClass);
+        put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
+    }
+
+    private void putSymmetricCipherImpl(String transformation, String implClass) {
+        put("Cipher." + transformation, implClass);
+        put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
+    }
+
+    /**
+     * Gets the {@link KeyStore} operation handle corresponding to the provided JCA crypto
+     * primitive.
+     *
+     * <p>The following primitives are supported: {@link Cipher} and {@link Mac}.
+     *
+     * @return KeyStore operation handle or {@code null} if the provided primitive's KeyStore
+     *         operation is not in progress.
+     *
+     * @throws IllegalArgumentException if the provided primitive is not supported or is not backed
+     *         by AndroidKeyStore provider.
+     */
+    public static Long getKeyStoreOperationHandle(Object cryptoPrimitive) {
+        if (cryptoPrimitive == null) {
+            throw new NullPointerException();
+        }
+        Object spi;
+        if (cryptoPrimitive instanceof Mac) {
+            spi = ((Mac) cryptoPrimitive).getSpi();
+        } else if (cryptoPrimitive instanceof Cipher) {
+            spi = ((Cipher) cryptoPrimitive).getSpi();
+        } else {
+            throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive);
+        }
+        if (!(spi instanceof KeyStoreCryptoOperation)) {
+            throw new IllegalArgumentException(
+                    "Crypto primitive not backed by AndroidKeyStore: " + cryptoPrimitive
+                    + ", spi: " + spi);
+        }
+        return ((KeyStoreCryptoOperation) spi).getOperationHandle();
     }
 }
diff --git a/keystore/java/android/security/CryptoOperationException.java b/keystore/java/android/security/CryptoOperationException.java
index ce64455..00c142f 100644
--- a/keystore/java/android/security/CryptoOperationException.java
+++ b/keystore/java/android/security/CryptoOperationException.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 /**
diff --git a/keystore/java/android/security/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java
new file mode 100644
index 0000000..0f19812
--- /dev/null
+++ b/keystore/java/android/security/EcIesParameterSpec.java
@@ -0,0 +1,287 @@
+package android.security;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
+/**
+ * {@link AlgorithmParameterSpec} for ECIES (Integrated Encryption Scheme using Elliptic Curve
+ * cryptography) based on {@code ISO/IEC 18033-2}.
+ *
+ * <p>ECIES is a hybrid authenticated encryption scheme. Encryption is performed using an Elliptic
+ * Curve (EC) public key. The resulting ciphertext can be decrypted only using the corresponding EC
+ * private key. The scheme is called hybrid because the EC key is only used to securely encapsulate
+ * symmetric key material. Encryption of plaintext and authentication of the corresponding
+ * ciphertext is performed using symmetric cryptography.
+ *
+ * <p>Encryption using ECIES consists of two stages:
+ * <ol>
+ * <li>Key Encapsulation Mechanism (KEM) randomly generates symmetric key material and securely
+ * encapsulates it in the output so that it can be extracted by the KEM when decrypting.
+ * Encapsulated key material is represented in the output as an EC point.</li>
+ * <li>The above symmetric key material is used by Data Encapsulation Mechanism (DEM) to encrypt the
+ * provided plaintext and authenticate the ciphertext. The resulting authenticated ciphertext is
+ * then output. When decrypting, the DEM first authenticates the ciphertext and, only if it
+ * authenticates, decrypts the ciphertext and outputs the plaintext.</li>
+ * </ol>
+ *
+ * <p>Details of KEM:
+ * <ul>
+ * <li>Only curves with cofactor of {@code 1} are supported.</li>
+ * <li>{@code CheckMode}, {@code OldCofactorMode}, {@code CofactorMode}, and {@code SingleHashMode}
+ * are {@code 0}.
+ * <li>Point format is specified by {@link #getKemPointFormat()}.</li>
+ * <li>KDF algorithm is specified by {@link #getKemKdfAlgorithm()}.</li>
+ * </ul>
+ *
+ * <p>Details of DEM:
+ * <ul>
+ * <li>Only DEM1-like mechanism is supported, with its symmetric cipher (SC) specified by
+ * {@link #getDemCipherTransformation()} (e.g., {@code AES/CBC/NoPadding} for standard DEM1) and
+ * MAC algorithm specified by {@link #getDemMacAlgorithm()} (e.g., {@code HmacSHA1} for standard
+ * DEM1).</li>
+ * </ul>
+ *
+ * @hide
+ */
+public class EcIesParameterSpec implements AlgorithmParameterSpec {
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {PointFormat.UNCOMPRESSED, PointFormat.COMPRESSED})
+    public @interface PointFormatEnum {}
+
+    /**
+     * Wire format of the EC point.
+     */
+    public static abstract class PointFormat {
+
+        private PointFormat() {}
+
+        /** Unspecified point format. */
+        public static final int UNSPECIFIED = -1;
+
+        /**
+         * Uncompressed point format: both coordinates are stored separately.
+         *
+         * <p>The wire format is byte {@code 0x04} followed by binary representation of the
+         * {@code x} coordinate followed by binary representation of the {@code y} coordinate. See
+         * {@code ISO 18033-2} section {@code 5.4.3}.
+         */
+        public static final int UNCOMPRESSED = 0;
+
+        /**
+         * Compressed point format: only one coordinate is stored.
+         *
+         * <p>The wire format is byte {@code 0x02} or {@code 0x03} (depending on the value of the
+         * stored coordinate) followed by the binary representation of the {@code x} coordinate.
+         * See {@code ISO 18033-2} section {@code 5.4.3}.
+         */
+        public static final int COMPRESSED = 1;
+    }
+
+    /**
+     * Default parameter spec: NIST P-256 curve (aka secp256r1 aka prime256v1), compressed point
+     * format, {@code HKDFwithSHA256}, DEM uses 128-bit AES GCM.
+     */
+    public static final EcIesParameterSpec DEFAULT = new EcIesParameterSpec(
+            "P-256",
+            PointFormat.COMPRESSED,
+            "HKDFwithSHA256",
+            "AES/GCM/NoPadding",
+            128,
+            null,
+            0);
+
+    private final String mKemCurveName;
+    private final @PointFormatEnum int mKemPointFormat;
+    private final String mKemKdfAlgorithm;
+    private final String mDemCipherTransformation;
+    private final int mDemCipherKeySize;
+    private final String mDemMacAlgorithm;
+    private final int mDemMacKeySize;
+
+    private EcIesParameterSpec(
+            String kemCurveName,
+            @PointFormatEnum int kemPointFormat,
+            String kemKdfAlgorithm,
+            String demCipherTransformation,
+            int demCipherKeySize,
+            String demMacAlgorithm,
+            int demMacKeySize) {
+        mKemCurveName = kemCurveName;
+        mKemPointFormat = kemPointFormat;
+        mKemKdfAlgorithm = kemKdfAlgorithm;
+        mDemCipherTransformation = demCipherTransformation;
+        mDemCipherKeySize = demCipherKeySize;
+        mDemMacAlgorithm = demMacAlgorithm;
+        mDemMacKeySize = demMacKeySize;
+    }
+
+    /**
+     * Returns KEM EC curve name (e.g., {@code secp256r1}) or {@code null} if not specified.
+     */
+    public String getKemCurveName() {
+        return mKemCurveName;
+    }
+
+    /**
+     * Returns KEM EC point wire format or {@link PointFormat#UNSPECIFIED} if not specified.
+     */
+    public @PointFormatEnum int getKemPointFormat() {
+        return mKemPointFormat;
+    }
+
+    /**
+     * Returns KEM KDF algorithm (e.g., {@code HKDFwithSHA256} or {@code KDF1withSHA1}) or
+     * {@code null} if not specified.
+     */
+    public String getKemKdfAlgorithm() {
+        return mKemKdfAlgorithm;
+    }
+
+    /**
+     * Returns DEM {@link Cipher} transformation (e.g., {@code AES/GCM/NoPadding} or
+     * {@code AES/CBC/PKCS7Padding}) or {@code null} if not specified.
+     *
+     * @see Cipher#getInstance(String)
+     * @see #getDemCipherKeySize()
+     */
+    public String getDemCipherTransformation() {
+        return mDemCipherTransformation;
+    }
+
+    /**
+     * Returns DEM {@link Cipher} key size in bits.
+     *
+     * @see #getDemCipherTransformation()
+     */
+    public int getDemCipherKeySize() {
+        return mDemCipherKeySize;
+    }
+
+    /**
+     * Returns DEM {@link Mac} algorithm (e.g., {@code HmacSHA256} or {@code HmacSHA1}) or
+     * {@code null} if not specified.
+     *
+     * @see Mac#getInstance(String)
+     * @see #getDemMacKeySize()
+     */
+    public String getDemMacAlgorithm() {
+        return mDemMacAlgorithm;
+    }
+
+    /**
+     * Returns DEM {@link Mac} key size in bits.
+     *
+     * @see #getDemCipherTransformation()
+     */
+    public int getDemMacKeySize() {
+        return mDemMacKeySize;
+    }
+
+    /**
+     * Builder of {@link EcIesParameterSpec}.
+     */
+    public static class Builder {
+        private String mKemCurveName;
+        private @PointFormatEnum int mKemPointFormat = PointFormat.UNSPECIFIED;
+        private String mKemKdfAlgorithm;
+        private String mDemCipherTransformation;
+        private int mDemCipherKeySize = 128;
+        private String mDemMacAlgorithm;
+        private int mDemMacKeySize = -1;
+
+        /**
+         * Sets KEM EC curve name. For example, {@code P-256} or {@code secp256r1}.
+         *
+         * <p>NOTE: Only curves with cofactor of {@code 1} are supported.
+         */
+        public Builder setKemCurveName(String name) {
+            mKemCurveName = name;
+            return this;
+        }
+
+        /**
+         * Sets KEM EC point wire format.
+         */
+        public Builder setKemPointFormat(@PointFormatEnum int pointFormat) {
+            mKemPointFormat = pointFormat;
+            return this;
+        }
+
+        /**
+         * Sets KEM KDF algorithm. For example, {@code HKDFwithSHA256}, {@code KDF2withSHA256}, or
+         * {@code KDF1withSHA1}.
+         */
+        public Builder setKemKdfAlgorithm(String algorithm) {
+            mKemKdfAlgorithm = algorithm;
+            return this;
+        }
+
+        /**
+         * Sets DEM {@link Cipher} transformation. For example, {@code AES/GCM/NoPadding},
+         * {@code AES/CBC/PKCS7Padding} or {@code AES/CTR/NoPadding}.
+         *
+         * @see Cipher#getInstance(String)
+         */
+        public Builder setDemCipherTransformation(String transformation) {
+            mDemCipherTransformation = transformation;
+            return this;
+        }
+
+        /**
+         * Returns DEM {@link Cipher} key size in bits.
+         *
+         * <p>The default value is {@code 128} bits.
+         *
+         * @see #setDemCipherTransformation(String)
+         */
+        public Builder setDemCipherKeySize(int sizeBits) {
+            mDemCipherKeySize = sizeBits;
+            return this;
+        }
+
+        /**
+         * Sets DEM {@link Mac} algorithm. For example, {@code HmacSHA256} or {@code HmacSHA1}.
+         *
+         * @see Mac#getInstance(String)
+         */
+        public Builder setDemMacAlgorithm(String algorithm) {
+            mDemMacAlgorithm = algorithm;
+            return this;
+        }
+
+        /**
+         * Sets DEM {@link Mac} key size in bits.
+         *
+         * <p>By default, {@code Mac} key size is the same as the {@code Cipher} key size.
+         *
+         * @see #setDemCipherKeySize(int)
+         */
+        public Builder setDemMacKeySize(int sizeBits) {
+            mDemMacKeySize = sizeBits;
+            return this;
+        }
+
+        /**
+         * Returns a new {@link EcIesParameterSpec} based on the current state of this builder.
+         */
+        public EcIesParameterSpec build() {
+            int demMacKeySize = (mDemMacKeySize != -1) ? mDemMacKeySize : mDemCipherKeySize;
+            return new EcIesParameterSpec(
+                    mKemCurveName,
+                    mKemPointFormat,
+                    mKemKdfAlgorithm,
+                    mDemCipherTransformation,
+                    mDemCipherKeySize,
+                    mDemMacAlgorithm,
+                    demMacKeySize
+                    );
+        }
+    }
+}
diff --git a/keystore/java/android/security/KeyExpiredException.java b/keystore/java/android/security/KeyExpiredException.java
new file mode 100644
index 0000000..35a5acc
--- /dev/null
+++ b/keystore/java/android/security/KeyExpiredException.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation failed because the employed key's validity end date
+ * is in the past.
+ *
+ * @hide
+ */
+public class KeyExpiredException extends CryptoOperationException {
+
+    /**
+     * Constructs a new {@code KeyExpiredException} without detail message and cause.
+     */
+    public KeyExpiredException() {
+        super("Key expired");
+    }
+
+    /**
+     * Constructs a new {@code KeyExpiredException} with the provided detail message and no cause.
+     */
+    public KeyExpiredException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code KeyExpiredException} with the provided detail message and cause.
+     */
+    public KeyExpiredException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 6274b70..4eedb24 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -1,15 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 import android.content.Context;
 import android.text.TextUtils;
 
-import java.security.cert.Certificate;
 import java.security.spec.AlgorithmParameterSpec;
-import java.util.Collections;
 import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
 
+import javax.crypto.Cipher;
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
 
@@ -17,13 +30,13 @@
  * {@link AlgorithmParameterSpec} for initializing a {@code KeyGenerator} that works with
  * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>.
  *
- * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API
- * using the {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up
- * some UI to ask the user to unlock or initialize the Android KeyStore facility.
+ * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API using the
+ * {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up some UI to
+ * ask the user to unlock or initialize the Android KeyStore facility.
  *
  * <p>After generation, the {@code keyStoreAlias} is used with the
  * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
- * interface to retrieve the {@link SecretKey} and its associated {@link Certificate} chain.
+ * interface to retrieve the {@link SecretKey}.
  *
  * @hide
  */
@@ -36,13 +49,13 @@
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
-    private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
-    private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
-    private final Integer mMinSecondsBetweenOperations;
-    private final Integer mMaxUsesPerBoot;
-    private final Set<Integer> mUserAuthenticators;
-    private final Integer mUserAuthenticationValidityDurationSeconds;
+    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final boolean mRandomizedEncryptionRequired;
+    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final int mUserAuthenticationValidityDurationSeconds;
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
     private KeyGeneratorSpec(
             Context context,
@@ -52,19 +65,19 @@
             Date keyValidityStart,
             Date keyValidityForOriginationEnd,
             Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum Integer purposes,
-            @KeyStoreKeyConstraints.PaddingEnum Integer padding,
-            @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
-            Integer minSecondsBetweenOperations,
-            Integer maxUsesPerBoot,
-            Set<Integer> userAuthenticators,
-            Integer userAuthenticationValidityDurationSeconds) {
+            @KeyStoreKeyConstraints.PurposeEnum int purposes,
+            @KeyStoreKeyConstraints.PaddingEnum int paddings,
+            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            boolean randomizedEncryptionRequired,
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            int userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
-        } else if ((userAuthenticationValidityDurationSeconds != null)
-                && (userAuthenticationValidityDurationSeconds < 0)) {
+        } else if ((userAuthenticationValidityDurationSeconds < 0)
+                && (userAuthenticationValidityDurationSeconds != -1)) {
             throw new IllegalArgumentException(
                     "userAuthenticationValidityDurationSeconds must not be negative");
         }
@@ -77,14 +90,12 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mPadding = padding;
-        mBlockMode = blockMode;
-        mMinSecondsBetweenOperations = minSecondsBetweenOperations;
-        mMaxUsesPerBoot = maxUsesPerBoot;
-        mUserAuthenticators = (userAuthenticators != null)
-                ? new HashSet<Integer>(userAuthenticators)
-                : Collections.<Integer>emptySet();
+        mPaddings = paddings;
+        mBlockModes = blockModes;
+        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+        mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -126,18 +137,16 @@
     }
 
     /**
-     * Gets the time instant after which the key is no long valid for decryption and verification.
+     * Gets the time instant after which the key is no longer valid for decryption and verification.
      *
      * @return instant or {@code null} if not restricted.
-     *
-     * @hide
      */
     public Date getKeyValidityForConsumptionEnd() {
         return mKeyValidityForConsumptionEnd;
     }
 
     /**
-     * Gets the time instant after which the key is no long valid for encryption and signing.
+     * Gets the time instant after which the key is no longer valid for encryption and signing.
      *
      * @return instant or {@code null} if not restricted.
      */
@@ -146,80 +155,71 @@
     }
 
     /**
-     * Gets the set of purposes for which the key can be used to the provided set of purposes.
-     *
-     * @return set of purposes or {@code null} if the key can be used for any purpose.
+     * Gets the set of purposes for which the key can be used.
      */
-    public @KeyStoreKeyConstraints.PurposeEnum Integer getPurposes() {
+    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the padding scheme to which the key is restricted.
-     *
-     * @return padding scheme or {@code null} if the padding scheme is not restricted.
+     * Gets the set of padding schemes to which the key is restricted.
      */
-    public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
-        return mPadding;
+    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
+        return mPaddings;
     }
 
     /**
-     * Gets the block mode to which the key is restricted when used for encryption or decryption.
-     *
-     * @return block more or {@code null} if block mode is not restricted.
-     *
-     * @hide
+     * Gets the set of block modes to which the key is restricted.
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
-        return mBlockMode;
+    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
+        return mBlockModes;
     }
 
     /**
-     * Gets the minimum number of seconds that must expire since the most recent use of the key
-     * before it can be used again.
-     *
-     * @return number of seconds or {@code null} if there is no restriction on how frequently a key
-     *         can be used.
-     *
-     * @hide
+     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+     * different ciphertexts for the same plaintext every time. The formal cryptographic property
+     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+     * IND-CPA})</em>. This property is important because it mitigates several classes of
+     * weaknesses due to which ciphertext may leak information about plaintext. For example, if a
+     * given plaintext always produces the same ciphertext, an attacker may see the repeated
+     * ciphertexts and be able to deduce something about the plaintext.
      */
-    public Integer getMinSecondsBetweenOperations() {
-        return mMinSecondsBetweenOperations;
+    public boolean isRandomizedEncryptionRequired() {
+        return mRandomizedEncryptionRequired;
     }
 
     /**
-     * Gets the number of times the key can be used without rebooting the device.
+     * Gets the set of user authenticators which protect access to this key. The key can only be
+     * used iff the user has authenticated to at least one of these user authenticators.
      *
-     * @return maximum number of times or {@code null} if there is no restriction.
-     * @hide
+     * @return user authenticators or {@code 0} if the key can be used without user authentication.
      */
-    public Integer getMaxUsesPerBoot() {
-        return mMaxUsesPerBoot;
-    }
-
-    /**
-     * Gets the user authenticators which protect access to this key. The key can only be used iff
-     * the user has authenticated to at least one of these user authenticators.
-     *
-     * @return user authenticators or empty set if the key can be used without user authentication.
-     *
-     * @hide
-     */
-    public Set<Integer> getUserAuthenticators() {
-        return new HashSet<Integer>(mUserAuthenticators);
+    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+        return mUserAuthenticators;
     }
 
     /**
      * Gets the duration of time (seconds) for which this key can be used after the user
      * successfully authenticates to one of the associated user authenticators.
      *
-     * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+     * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
+     */
+    public int getUserAuthenticationValidityDurationSeconds() {
+        return mUserAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
      *
      * @hide
      */
-    public Integer getUserAuthenticationValidityDurationSeconds() {
-        return mUserAuthenticationValidityDurationSeconds;
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -237,13 +237,13 @@
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
         private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
-        private @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
-        private @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
-        private Integer mMinSecondsBetweenOperations;
-        private Integer mMaxUsesPerBoot;
-        private Set<Integer> mUserAuthenticators;
-        private Integer mUserAuthenticationValidityDurationSeconds;
+        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private boolean mRandomizedEncryptionRequired = true;
+        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private int mUserAuthenticationValidityDurationSeconds = -1;
+        private boolean mInvalidatedOnNewFingerprintEnrolled;
 
         /**
          * Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -299,11 +299,9 @@
         /**
          * Sets the time instant before which the key is not yet valid.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityStart(Date startDate) {
             mKeyValidityStart = startDate;
@@ -313,13 +311,11 @@
         /**
          * Sets the time instant after which the key is no longer valid.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityStart(Date)
          * @see #setKeyValidityForConsumptionEnd(Date)
          * @see #setKeyValidityForOriginationEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityEnd(Date endDate) {
             setKeyValidityForOriginationEnd(endDate);
@@ -330,11 +326,9 @@
         /**
          * Sets the time instant after which the key is no longer valid for encryption and signing.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForConsumptionEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityForOriginationEnd(Date endDate) {
             mKeyValidityForOriginationEnd = endDate;
@@ -345,11 +339,9 @@
          * Sets the time instant after which the key is no longer valid for decryption and
          * verification.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForOriginationEnd(Date)
-         *
-         * @hide
          */
         public Builder setKeyValidityForConsumptionEnd(Date endDate) {
             mKeyValidityForConsumptionEnd = endDate;
@@ -357,11 +349,9 @@
         }
 
         /**
-         * Restricts the purposes for which the key can be used to the provided set of purposes.
+         * Restricts the key to being used only for the provided set of purposes.
          *
-         * <p>By default, the key can be used for encryption, decryption, signing, and verification.
-         *
-         * @hide
+         * <p>This restriction must be specified. There is no default.
          */
         public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
             mPurposes = purposes;
@@ -369,53 +359,61 @@
         }
 
         /**
-         * Restricts the key to being used only with the provided padding scheme. Attempts to use
+         * Restricts the key to being used only with the provided padding schemes. Attempts to use
          * the key with any other padding will be rejected.
          *
          * <p>This restriction must be specified for keys which are used for encryption/decryption.
-         *
-         * @hide
          */
-        public Builder setPadding(@KeyStoreKeyConstraints.PaddingEnum int padding) {
-            mPadding = padding;
+        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
+            mPaddings = paddings;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block mode when encrypting or
-         * decrypting. Attempts to use the key with any other block modes will be rejected.
+         * Restricts the key to being used only with the provided block modes. Attempts to use the
+         * key with any other block modes will be rejected.
          *
          * <p>This restriction must be specified for keys which are used for encryption/decryption.
-         *
-         * @hide
          */
-        public Builder setBlockMode(@KeyStoreKeyConstraints.BlockModeEnum int blockMode) {
-            mBlockMode = blockMode;
+        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
+            mBlockModes = blockModes;
             return this;
         }
 
         /**
-         * Sets the minimum number of seconds that must expire since the most recent use of the key
-         * before it can be used again.
+         * Sets whether encryption using this key must be sufficiently randomized to produce
+         * different ciphertexts for the same plaintext every time. The formal cryptographic
+         * property being required is <em>indistinguishability under chosen-plaintext attack
+         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+         * of weaknesses due to which ciphertext may leak information about plaintext. For example,
+         * if a given plaintext always produces the same ciphertext, an attacker may see the
+         * repeated ciphertexts and be able to deduce something about the plaintext.
          *
-         * <p>By default, there is no restriction on how frequently a key can be used.
+         * <p>By default, {@code IND-CPA} is required.
          *
-         * @hide
+         * <p>When {@code IND-CPA} is required:
+         * <ul>
+         * <li>block modes which do not offer {@code IND-CPA}, such as {@code ECB}, are prohibited;
+         * </li>
+         * <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM},
+         * caller-provided IVs are rejected when encrypting, to ensure that only random IVs are
+         * used.</li>
+         *
+         * <p>Before disabling this requirement, consider the following approaches instead:
+         * <ul>
+         * <li>If you are generating a random IV for encryption and then initializing a {@code}
+         * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
+         * instead. This will occur if the {@code Cipher} is initialized for encryption without an
+         * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
+         * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
+         * random, such as the name of the file being encrypted, or transaction ID, or password,
+         * or a device identifier), consider changing your design to use a random IV which will then
+         * be provided in addition to the ciphertext to the entities which need to decrypt the
+         * ciphertext.</li>
+         * </ul>
          */
-        public Builder setMinSecondsBetweenOperations(int seconds) {
-            mMinSecondsBetweenOperations = seconds;
-            return this;
-        }
-
-        /**
-         * Sets the maximum number of times a key can be used without rebooting the device.
-         *
-         * <p>By default, the key can be used for an unlimited number of times.
-         *
-         * @hide
-         */
-        public Builder setMaxUsesPerBoot(int count) {
-            mMaxUsesPerBoot = count;
+        public Builder setRandomizedEncryptionRequired(boolean required) {
+            mRandomizedEncryptionRequired = required;
             return this;
         }
 
@@ -429,12 +427,10 @@
          *        without user authentication.
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
-         *
-         * @hide
          */
-        public Builder setUserAuthenticators(Set<Integer> userAuthenticators) {
-            mUserAuthenticators =
-                    (userAuthenticators != null) ? new HashSet<Integer>(userAuthenticators) : null;
+        public Builder setUserAuthenticators(
+                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+            mUserAuthenticators = userAuthenticators;
             return this;
         }
 
@@ -447,12 +443,26 @@
          * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
          *        every use of the key.
          *
+         * @see #setUserAuthenticators(int)
+         */
+        public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
+            mUserAuthenticationValidityDurationSeconds = seconds;
+            return this;
+        }
+
+        /**
+         * Sets whether this key must be invalidated (permanently) once a new fingerprint is
+         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+         * protecting access to the key.
+         *
+         * <p>By default, enrolling a new fingerprint does not invalidate the key.
+         *
          * @see #setUserAuthenticators(Set)
          *
          * @hide
          */
-        public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
-            mUserAuthenticationValidityDurationSeconds = seconds;
+        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+            mInvalidatedOnNewFingerprintEnrolled = invalidated;
             return this;
         }
 
@@ -462,10 +472,20 @@
          * @throws IllegalArgumentException if a required field is missing or violates a constraint.
          */
         public KeyGeneratorSpec build() {
-            return new KeyGeneratorSpec(mContext, mKeystoreAlias, mFlags, mKeySize,
-                    mKeyValidityStart, mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd,
-                    mPurposes, mPadding, mBlockMode, mMinSecondsBetweenOperations, mMaxUsesPerBoot,
-                    mUserAuthenticators, mUserAuthenticationValidityDurationSeconds);
+            return new KeyGeneratorSpec(mContext,
+                    mKeystoreAlias,
+                    mFlags,
+                    mKeySize,
+                    mKeyValidityStart,
+                    mKeyValidityForOriginationEnd,
+                    mKeyValidityForConsumptionEnd,
+                    mPurposes,
+                    mPaddings,
+                    mBlockModes,
+                    mRandomizedEncryptionRequired,
+                    mUserAuthenticators,
+                    mUserAuthenticationValidityDurationSeconds,
+                    mInvalidatedOnNewFingerprintEnrolled);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyNotYetValidException.java b/keystore/java/android/security/KeyNotYetValidException.java
new file mode 100644
index 0000000..f1c2cac
--- /dev/null
+++ b/keystore/java/android/security/KeyNotYetValidException.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation failed because the employed key's validity start date
+ * is in the future.
+ *
+ * @hide
+ */
+public class KeyNotYetValidException extends CryptoOperationException {
+
+    /**
+     * Constructs a new {@code KeyNotYetValidException} without detail message and cause.
+     */
+    public KeyNotYetValidException() {
+        super("Key not yet valid");
+    }
+
+    /**
+     * Constructs a new {@code KeyNotYetValidException} with the provided detail message and no
+     * cause.
+     */
+    public KeyNotYetValidException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code KeyNotYetValidException} with the provided detail message and cause.
+     */
+    public KeyNotYetValidException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index cc097aa..4ca220d 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -72,6 +72,28 @@
 
     private final int mFlags;
 
+    private final Date mKeyValidityStart;
+
+    private final Date mKeyValidityForOriginationEnd;
+
+    private final Date mKeyValidityForConsumptionEnd;
+
+    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+
+    private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
+
+    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+
+    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+
+    private final boolean mRandomizedEncryptionRequired;
+
+    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+
+    private final int mUserAuthenticationValidityDurationSeconds;
+
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
+
     /**
      * Parameter specification for the "{@code AndroidKeyPairGenerator}"
      * instance of the {@link java.security.KeyPairGenerator} API. The
@@ -106,7 +128,18 @@
      */
     public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
             AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
-            Date startDate, Date endDate, int flags) {
+            Date startDate, Date endDate, int flags,
+            Date keyValidityStart,
+            Date keyValidityForOriginationEnd,
+            Date keyValidityForConsumptionEnd,
+            @KeyStoreKeyConstraints.PurposeEnum int purposes,
+            @KeyStoreKeyConstraints.DigestEnum int digests,
+            @KeyStoreKeyConstraints.PaddingEnum int paddings,
+            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            boolean randomizedEncryptionRequired,
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            int userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
         if (context == null) {
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
@@ -121,6 +154,10 @@
             throw new IllegalArgumentException("endDate == null");
         } else if (endDate.before(startDate)) {
             throw new IllegalArgumentException("endDate < startDate");
+        } else if ((userAuthenticationValidityDurationSeconds < 0)
+                && (userAuthenticationValidityDurationSeconds != -1)) {
+            throw new IllegalArgumentException(
+                    "userAuthenticationValidityDurationSeconds must not be negative");
         }
 
         mContext = context;
@@ -133,6 +170,48 @@
         mStartDate = startDate;
         mEndDate = endDate;
         mFlags = flags;
+        mKeyValidityStart = keyValidityStart;
+        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
+        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mPurposes = purposes;
+        mDigests = digests;
+        mPaddings = paddings;
+        mBlockModes = blockModes;
+        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+        mUserAuthenticators = userAuthenticators;
+        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
+     * TODO: Remove this constructor once tests are switched over to the new one above.
+     * @hide
+     */
+    public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
+            AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
+            Date startDate, Date endDate, int flags) {
+
+        this(context,
+                keyStoreAlias,
+                keyType,
+                keySize,
+                spec,
+                subjectDN,
+                serialNumber,
+                startDate,
+                endDate,
+                flags,
+                startDate,
+                endDate,
+                endDate,
+                0,
+                0,
+                0,
+                0,
+                true,
+                0,
+                -1,
+                false);
     }
 
     /**
@@ -222,6 +301,135 @@
     }
 
     /**
+     * Gets the time instant before which the key pair is not yet valid.
+     *
+     * @return instant or {@code null} if not restricted.
+     *
+     * @hide
+     */
+    public Date getKeyValidityStart() {
+        return mKeyValidityStart;
+    }
+
+    /**
+     * Gets the time instant after which the key pair is no longer valid for decryption and
+     * verification.
+     *
+     * @return instant or {@code null} if not restricted.
+     *
+     * @hide
+     */
+    public Date getKeyValidityForConsumptionEnd() {
+        return mKeyValidityForConsumptionEnd;
+    }
+
+    /**
+     * Gets the time instant after which the key pair is no longer valid for encryption and signing.
+     *
+     * @return instant or {@code null} if not restricted.
+     *
+     * @hide
+     */
+    public Date getKeyValidityForOriginationEnd() {
+        return mKeyValidityForOriginationEnd;
+    }
+
+    /**
+     * Gets the set of purposes for which the key can be used.
+     *
+     * @hide
+     */
+    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+        return mPurposes;
+    }
+
+    /**
+     * Gets the set of digests to which the key is restricted.
+     *
+     * @hide
+     */
+    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
+        return mDigests;
+    }
+
+    /**
+     * Gets the set of padding schemes to which the key is restricted.
+     *
+     * @hide
+     */
+    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
+        return mPaddings;
+    }
+
+    /**
+     * Gets the set of block modes to which the key is restricted.
+     *
+     * @hide
+     */
+    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
+        return mBlockModes;
+    }
+
+    /**
+     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+     * different ciphertexts for the same plaintext every time. The formal cryptographic property
+     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+     * IND-CPA})</em>. This property is important because it mitigates several classes of
+     * weaknesses due to which ciphertext may leak information about plaintext.  For example, if a
+     * given plaintext always produces the same ciphertext, an attacker may see the repeated
+     * ciphertexts and be able to deduce something about the plaintext.
+     *
+     * @hide
+     */
+    public boolean isRandomizedEncryptionRequired() {
+        return mRandomizedEncryptionRequired;
+    }
+
+    /**
+     * Gets the set of user authenticators which protect access to the private key. The key can only
+     * be used iff the user has authenticated to at least one of these user authenticators.
+     *
+     * <p>This restriction applies only to private key operations. Public key operations are not
+     * restricted.
+     *
+     * @return user authenticators or {@code 0} if the key can be used without user authentication.
+     *
+     * @hide
+     */
+    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+        return mUserAuthenticators;
+    }
+
+    /**
+     * Gets the duration of time (seconds) for which the private key can be used after the user
+     * successfully authenticates to one of the associated user authenticators.
+     *
+     * <p>This restriction applies only to private key operations. Public key operations are not
+     * restricted.
+     *
+     * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
+     *         is required for every use of the key.
+     *
+     * @hide
+     */
+    public int getUserAuthenticationValidityDurationSeconds() {
+        return mUserAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
+     *
+     * @hide
+     */
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
      * Builder class for {@link KeyPairGeneratorSpec} objects.
      * <p>
      * This will build a parameter spec for use with the <a href="{@docRoot}
@@ -263,6 +471,28 @@
 
         private int mFlags;
 
+        private Date mKeyValidityStart;
+
+        private Date mKeyValidityForOriginationEnd;
+
+        private Date mKeyValidityForConsumptionEnd;
+
+        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+
+        private @KeyStoreKeyConstraints.DigestEnum int mDigests;
+
+        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+
+        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+
+        private boolean mRandomizedEncryptionRequired = true;
+
+        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+
+        private int mUserAuthenticationValidityDurationSeconds = -1;
+
+        private boolean mInvalidatedOnNewFingerprintEnrolled;
+
         /**
          * Creates a new instance of the {@code Builder} with the given
          * {@code context}. The {@code context} passed in may be used to pop up
@@ -389,14 +619,230 @@
         }
 
         /**
+         * Sets the time instant before which the key is not yet valid.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * @see #setKeyValidityEnd(Date)
+         *
+         * @hide
+         */
+        public Builder setKeyValidityStart(Date startDate) {
+            mKeyValidityStart = startDate;
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * @see #setKeyValidityStart(Date)
+         * @see #setKeyValidityForConsumptionEnd(Date)
+         * @see #setKeyValidityForOriginationEnd(Date)
+         *
+         * @hide
+         */
+        public Builder setKeyValidityEnd(Date endDate) {
+            setKeyValidityForOriginationEnd(endDate);
+            setKeyValidityForConsumptionEnd(endDate);
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid for encryption and signing.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * @see #setKeyValidityForConsumptionEnd(Date)
+         *
+         * @hide
+         */
+        public Builder setKeyValidityForOriginationEnd(Date endDate) {
+            mKeyValidityForOriginationEnd = endDate;
+            return this;
+        }
+
+        /**
+         * Sets the time instant after which the key is no longer valid for decryption and
+         * verification.
+         *
+         * <p>By default, the key is valid at any instant.
+         *
+         * @see #setKeyValidityForOriginationEnd(Date)
+         *
+         * @hide
+         */
+        public Builder setKeyValidityForConsumptionEnd(Date endDate) {
+            mKeyValidityForConsumptionEnd = endDate;
+            return this;
+        }
+
+        /**
+         * Restricts the key to being used only for the provided set of purposes.
+         *
+         * <p>This restriction must be specified. There is no default.
+         *
+         * @hide
+         */
+        public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+            mPurposes = purposes;
+            return this;
+        }
+
+        /**
+         * Restricts the key to being used only with the provided digests. Attempts to use the key
+         * with any other digests be rejected.
+         *
+         * <p>This restriction must be specified for keys which are used for signing/verification.
+         *
+         * @hide
+         */
+        public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
+            mDigests = digests;
+            return this;
+        }
+
+        /**
+         * Restricts the key to being used only with the provided padding schemes. Attempts to use
+         * the key with any other padding will be rejected.
+         *
+         * <p>This restriction must be specified for keys which are used for encryption/decryption.
+         *
+         * @hide
+         */
+        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
+            mPaddings = paddings;
+            return this;
+        }
+
+        /**
+         * Restricts the key to being used only with the provided block mode when encrypting or
+         * decrypting. Attempts to use the key with any other block modes will be rejected.
+         *
+         * <p>This restriction must be specified for keys which are used for encryption/decryption.
+         *
+         * @hide
+         */
+        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
+            mBlockModes = blockModes;
+            return this;
+        }
+
+        /**
+         * Sets whether encryption using this key must be sufficiently randomized to produce
+         * different ciphertexts for the same plaintext every time. The formal cryptographic
+         * property being required is <em>indistinguishability under chosen-plaintext attack
+         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+         * of weaknesses due to which ciphertext may leak information about plaintext. For example,
+         * if a given plaintext always produces the same ciphertext, an attacker may see the
+         * repeated ciphertexts and be able to deduce something about the plaintext.
+         *
+         * <p>By default, {@code IND-CPA} is required.
+         *
+         * <p>When {@code IND-CPA} is required, encryption/decryption transformations which do not
+         * offer {@code IND-CPA}, such as RSA without padding, are prohibited.
+         *
+         * <p>Before disabling this requirement, consider the following approaches instead:
+         * <ul>
+         * <li>If you are using RSA encryption without padding, consider switching to padding
+         * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
+         * </ul>
+         *
+         * @hide
+         */
+        public Builder setRandomizedEncryptionRequired(boolean required) {
+            mRandomizedEncryptionRequired = required;
+            return this;
+        }
+
+        /**
+         * Sets the user authenticators which protect access to this key. The key can only be used
+         * iff the user has authenticated to at least one of these user authenticators.
+         *
+         * <p>By default, the key can be used without user authentication.
+         *
+         * <p>This restriction applies only to private key operations. Public key operations are not
+         * restricted.
+         *
+         * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed
+         *        without user authentication.
+         *
+         * @see #setUserAuthenticationValidityDurationSeconds(int)
+         *
+         * @hide
+         */
+        public Builder setUserAuthenticators(
+                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+            mUserAuthenticators = userAuthenticators;
+            return this;
+        }
+
+        /**
+         * Sets the duration of time (seconds) for which this key can be used after the user
+         * successfully authenticates to one of the associated user authenticators.
+         *
+         * <p>By default, the user needs to authenticate for every use of the key.
+         *
+         * <p>This restriction applies only to private key operations. Public key operations are not
+         * restricted.
+         *
+         * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
+         *        every use of the key.
+         *
+         * @see #setUserAuthenticators(int)
+         *
+         * @hide
+         */
+        public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
+            mUserAuthenticationValidityDurationSeconds = seconds;
+            return this;
+        }
+
+        /**
+         * Sets whether this key must be invalidated (permanently) once a new fingerprint is
+         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+         * protecting access to the key.
+         *
+         * <p>By default, enrolling a new fingerprint does not invalidate the key.
+         *
+         * @see #setUserAuthenticators(Set)
+         *
+         * @hide
+         */
+        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+            mInvalidatedOnNewFingerprintEnrolled = invalidated;
+            return this;
+        }
+
+        /**
          * Builds the instance of the {@code KeyPairGeneratorSpec}.
          *
          * @throws IllegalArgumentException if a required field is missing
          * @return built instance of {@code KeyPairGeneratorSpec}
          */
         public KeyPairGeneratorSpec build() {
-            return new KeyPairGeneratorSpec(mContext, mKeystoreAlias, mKeyType, mKeySize, mSpec,
-                    mSubjectDN, mSerialNumber, mStartDate, mEndDate, mFlags);
+            return new KeyPairGeneratorSpec(mContext,
+                    mKeystoreAlias,
+                    mKeyType,
+                    mKeySize,
+                    mSpec,
+                    mSubjectDN,
+                    mSerialNumber,
+                    mStartDate,
+                    mEndDate,
+                    mFlags,
+                    mKeyValidityStart,
+                    mKeyValidityForOriginationEnd,
+                    mKeyValidityForConsumptionEnd,
+                    mPurposes,
+                    mDigests,
+                    mPaddings,
+                    mBlockModes,
+                    mRandomizedEncryptionRequired,
+                    mUserAuthenticators,
+                    mUserAuthenticationValidityDurationSeconds,
+                    mInvalidatedOnNewFingerprintEnrolled);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 94a479b..5af0527 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -26,6 +26,7 @@
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterBlob;
+import android.security.keymaster.KeymasterDefs;
 import android.security.keymaster.OperationResult;
 import android.util.Log;
 
@@ -506,4 +507,60 @@
             return SYSTEM_ERROR;
         }
     }
+
+    public static KeyStoreException getKeyStoreException(int errorCode) {
+        if (errorCode > 0) {
+            // KeyStore layer error
+            switch (errorCode) {
+                case NO_ERROR:
+                    return new KeyStoreException(errorCode, "OK");
+                case LOCKED:
+                    return new KeyStoreException(errorCode, "Keystore locked");
+                case UNINITIALIZED:
+                    return new KeyStoreException(errorCode, "Keystore not initialized");
+                case SYSTEM_ERROR:
+                    return new KeyStoreException(errorCode, "System error");
+                case PERMISSION_DENIED:
+                    return new KeyStoreException(errorCode, "Permission denied");
+                case KEY_NOT_FOUND:
+                    return new KeyStoreException(errorCode, "Key not found");
+                case VALUE_CORRUPTED:
+                    return new KeyStoreException(errorCode, "Key blob corrupted");
+                default:
+                    return new KeyStoreException(errorCode, String.valueOf(errorCode));
+            }
+        } else {
+            // Keymaster layer error
+            switch (errorCode) {
+                case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
+                    // The name of this parameter significantly differs between Keymaster and
+                    // framework APIs. Use the framework wording to make life easier for developers.
+                    return new KeyStoreException(errorCode,
+                            "Invalid user authentication validity duration");
+                default:
+                    return new KeyStoreException(errorCode,
+                            KeymasterDefs.getErrorMessage(errorCode));
+            }
+        }
+    }
+
+    public static CryptoOperationException getCryptoOperationException(KeyStoreException e) {
+        switch (e.getErrorCode()) {
+            case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
+                return new KeyExpiredException();
+            case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
+                return new KeyNotYetValidException();
+            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
+                return new UserNotAuthenticatedException();
+            // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
+            // case KeymasterDefs.KM_ERROR_TBD
+            //     return new NewFingerprintEnrolledException();
+            default:
+                return new CryptoOperationException("Crypto operation failed", e);
+        }
+    }
+
+    public static CryptoOperationException getCryptoOperationException(int errorCode) {
+        return getCryptoOperationException(getKeyStoreException(errorCode));
+    }
 }
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
new file mode 100644
index 0000000..487eac0
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -0,0 +1,603 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.os.IBinder;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keymaster.OperationResult;
+
+import java.security.AlgorithmParameters;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.util.Arrays;
+
+import javax.crypto.AEADBadTagException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.CipherSpi;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.ShortBufferException;
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * Base class for {@link CipherSpi} providing Android KeyStore backed ciphers.
+ *
+ * @hide
+ */
+public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
+
+    public abstract static class AES extends KeyStoreCipherSpi {
+        protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
+                @KeyStoreKeyConstraints.PaddingEnum int padding, boolean ivUsed) {
+            super(KeyStoreKeyConstraints.Algorithm.AES,
+                    blockMode,
+                    padding,
+                    16,
+                    ivUsed);
+        }
+
+        public abstract static class ECB extends AES {
+            protected ECB(@KeyStoreKeyConstraints.PaddingEnum int padding) {
+                super(KeyStoreKeyConstraints.BlockMode.ECB, padding, false);
+            }
+
+            public static class NoPadding extends ECB {
+                public NoPadding() {
+                    super(KeyStoreKeyConstraints.Padding.NONE);
+                }
+            }
+
+            public static class PKCS7Padding extends ECB {
+                public PKCS7Padding() {
+                    super(KeyStoreKeyConstraints.Padding.PKCS7);
+                }
+            }
+        }
+
+        public abstract static class CBC extends AES {
+            protected CBC(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
+                super(KeyStoreKeyConstraints.BlockMode.CBC, padding, true);
+            }
+
+            public static class NoPadding extends CBC {
+                public NoPadding() {
+                    super(KeyStoreKeyConstraints.Padding.NONE);
+                }
+            }
+
+            public static class PKCS7Padding extends CBC {
+                public PKCS7Padding() {
+                    super(KeyStoreKeyConstraints.Padding.PKCS7);
+                }
+            }
+        }
+
+        public abstract static class CTR extends AES {
+            protected CTR(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
+                super(KeyStoreKeyConstraints.BlockMode.CTR, padding, true);
+            }
+
+            public static class NoPadding extends CTR {
+                public NoPadding() {
+                    super(KeyStoreKeyConstraints.Padding.NONE);
+                }
+            }
+        }
+    }
+
+    private final KeyStore mKeyStore;
+    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
+    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode;
+    private final @KeyStoreKeyConstraints.PaddingEnum int mPadding;
+    private final int mBlockSizeBytes;
+
+    /** Whether this transformation requires an IV. */
+    private final boolean mIvRequired;
+
+    // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
+    // doFinal finishes.
+    protected boolean mEncrypting;
+    private KeyStoreSecretKey mKey;
+    private SecureRandom mRng;
+    private boolean mFirstOperationInitiated;
+    private byte[] mIv;
+    /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
+    private boolean mIvHasBeenUsed;
+
+    // Fields below must be reset after doFinal
+    private byte[] mAdditionalEntropyForBegin;
+
+    /**
+     * Token referencing this operation inside keystore service. It is initialized by
+     * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some
+     * error conditions in between.
+     */
+    private IBinder mOperationToken;
+    private Long mOperationHandle;
+    private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
+
+    protected KeyStoreCipherSpi(
+            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+            @KeyStoreKeyConstraints.BlockModeEnum int blockMode,
+            @KeyStoreKeyConstraints.PaddingEnum int padding,
+            int blockSizeBytes,
+            boolean ivUsed) {
+        mKeyStore = KeyStore.getInstance();
+        mAlgorithm = algorithm;
+        mBlockMode = blockMode;
+        mPadding = padding;
+        mBlockSizeBytes = blockSizeBytes;
+        mIvRequired = ivUsed;
+    }
+
+    @Override
+    protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+        init(opmode, key, random);
+        initAlgorithmSpecificParameters();
+        ensureKeystoreOperationInitialized();
+    }
+
+    @Override
+    protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random)
+            throws InvalidKeyException, InvalidAlgorithmParameterException {
+        init(opmode, key, random);
+        initAlgorithmSpecificParameters(params);
+        ensureKeystoreOperationInitialized();
+    }
+
+    @Override
+    protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
+            SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
+        init(opmode, key, random);
+        initAlgorithmSpecificParameters(params);
+        ensureKeystoreOperationInitialized();
+    }
+
+    private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
+        resetAll();
+        if (!(key instanceof KeyStoreSecretKey)) {
+            throw new InvalidKeyException(
+                    "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
+        }
+        mKey = (KeyStoreSecretKey) key;
+        mRng = random;
+        mIv = null;
+        mFirstOperationInitiated = false;
+
+        if ((opmode != Cipher.ENCRYPT_MODE) && (opmode != Cipher.DECRYPT_MODE)) {
+            throw new UnsupportedOperationException(
+                    "Only ENCRYPT and DECRYPT modes supported. Mode: " + opmode);
+        }
+        mEncrypting = opmode == Cipher.ENCRYPT_MODE;
+    }
+
+    private void resetAll() {
+        IBinder operationToken = mOperationToken;
+        if (operationToken != null) {
+            mOperationToken = null;
+            mKeyStore.abort(operationToken);
+        }
+        mEncrypting = false;
+        mKey = null;
+        mRng = null;
+        mFirstOperationInitiated = false;
+        mIv = null;
+        mIvHasBeenUsed = false;
+        mAdditionalEntropyForBegin = null;
+        mOperationToken = null;
+        mOperationHandle = null;
+        mMainDataStreamer = null;
+    }
+
+    private void resetWhilePreservingInitState() {
+        IBinder operationToken = mOperationToken;
+        if (operationToken != null) {
+            mOperationToken = null;
+            mKeyStore.abort(operationToken);
+        }
+        mOperationHandle = null;
+        mMainDataStreamer = null;
+        mAdditionalEntropyForBegin = null;
+    }
+
+    private void ensureKeystoreOperationInitialized() {
+        if (mMainDataStreamer != null) {
+            return;
+        }
+        if (mKey == null) {
+            throw new IllegalStateException("Not initialized");
+        }
+        if ((mEncrypting) && (mIvRequired) && (mIvHasBeenUsed)) {
+            // IV is being reused for encryption: this violates security best practices.
+            throw new IllegalStateException(
+                    "IV has already been used. Reusing IV in encryption mode violates security best"
+                    + " practices.");
+        }
+
+        KeymasterArguments keymasterInputArgs = new KeymasterArguments();
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mBlockMode);
+        keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mPadding);
+        addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
+
+        KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
+        OperationResult opResult = mKeyStore.begin(
+                mKey.getAlias(),
+                mEncrypting ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT,
+                true, // permit aborting this operation if keystore runs out of resources
+                keymasterInputArgs,
+                mAdditionalEntropyForBegin,
+                keymasterOutputArgs);
+        mAdditionalEntropyForBegin = null;
+        if (opResult == null) {
+            throw new KeyStoreConnectException();
+        } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+            throw KeyStore.getCryptoOperationException(opResult.resultCode);
+        }
+
+        if (opResult.token == null) {
+            throw new CryptoOperationException("Keystore returned null operation token");
+        }
+        mOperationToken = opResult.token;
+        mOperationHandle = opResult.operationHandle;
+        loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
+        mFirstOperationInitiated = true;
+        mIvHasBeenUsed = true;
+        mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer(
+                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
+                        mKeyStore, opResult.token));
+    }
+
+    @Override
+    protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
+        ensureKeystoreOperationInitialized();
+
+        if (inputLen == 0) {
+            return null;
+        }
+
+        byte[] output;
+        try {
+            output = mMainDataStreamer.update(input, inputOffset, inputLen);
+        } catch (KeyStoreException e) {
+            throw KeyStore.getCryptoOperationException(e);
+        }
+
+        if (output.length == 0) {
+            return null;
+        }
+
+        return output;
+    }
+
+    @Override
+    protected int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
+            int outputOffset) throws ShortBufferException {
+        byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
+        if (outputCopy == null) {
+            return 0;
+        }
+        int outputAvailable = output.length - outputOffset;
+        if (outputCopy.length > outputAvailable) {
+            throw new ShortBufferException("Output buffer too short. Produced: "
+                    + outputCopy.length + ", available: " + outputAvailable);
+        }
+        System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
+        return outputCopy.length;
+    }
+
+    @Override
+    protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
+            throws IllegalBlockSizeException, BadPaddingException {
+        ensureKeystoreOperationInitialized();
+
+        byte[] output;
+        try {
+            output = mMainDataStreamer.doFinal(input, inputOffset, inputLen);
+        } catch (KeyStoreException e) {
+            switch (e.getErrorCode()) {
+                case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
+                    throw new IllegalBlockSizeException();
+                case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
+                    throw new BadPaddingException();
+                case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
+                    throw new AEADBadTagException();
+                default:
+                    throw KeyStore.getCryptoOperationException(e);
+            }
+        }
+
+        resetWhilePreservingInitState();
+        return output;
+    }
+
+    @Override
+    protected int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
+            int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
+            BadPaddingException {
+        byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
+        if (outputCopy == null) {
+            return 0;
+        }
+        int outputAvailable = output.length - outputOffset;
+        if (outputCopy.length > outputAvailable) {
+            throw new ShortBufferException("Output buffer too short. Produced: "
+                    + outputCopy.length + ", available: " + outputAvailable);
+        }
+        System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
+        return outputCopy.length;
+    }
+
+    @Override
+    protected int engineGetBlockSize() {
+        return mBlockSizeBytes;
+    }
+
+    @Override
+    protected byte[] engineGetIV() {
+        return (mIv != null) ? mIv.clone() : null;
+    }
+
+    @Override
+    protected int engineGetOutputSize(int inputLen) {
+        return inputLen + 3 * engineGetBlockSize();
+    }
+
+    @Override
+    protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
+        // This should never be invoked because all algorithms registered with the AndroidKeyStore
+        // provide explicitly specify block mode.
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    protected void engineSetPadding(String arg0) throws NoSuchPaddingException {
+        // This should never be invoked because all algorithms registered with the AndroidKeyStore
+        // provide explicitly specify padding mode.
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void finalize() throws Throwable {
+        try {
+            IBinder operationToken = mOperationToken;
+            if (operationToken != null) {
+                mKeyStore.abort(operationToken);
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    @Override
+    public Long getOperationHandle() {
+        return mOperationHandle;
+    }
+
+    // The methods below may need to be overridden by subclasses that use algorithm-specific
+    // parameters.
+
+    /**
+     * Returns algorithm-specific parameters used by this {@code CipherSpi} instance or {@code null}
+     * if no algorithm-specific parameters are used.
+     *
+     * <p>This implementation only handles the IV parameter.
+     */
+    @Override
+    protected AlgorithmParameters engineGetParameters() {
+        if (!mIvRequired) {
+            return null;
+        }
+        if ((mIv != null) && (mIv.length > 0)) {
+            try {
+                AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
+                params.init(new IvParameterSpec(mIv));
+                return params;
+            } catch (NoSuchAlgorithmException e) {
+                throw new RuntimeException("Failed to obtain AES AlgorithmParameters", e);
+            } catch (InvalidParameterSpecException e) {
+                throw new RuntimeException(
+                        "Failed to initialize AES AlgorithmParameters with an IV", e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Invoked by {@code engineInit} to initialize algorithm-specific parameters. These parameters
+     * may need to be stored to be reused after {@code doFinal}.
+     *
+     * <p>The default implementation only handles the IV parameters.
+     *
+     * @param params algorithm parameters.
+     *
+     * @throws InvalidAlgorithmParameterException if some/all of the parameters cannot be
+     *         automatically configured and thus {@code Cipher.init} needs to be invoked with
+     *         explicitly provided parameters.
+     */
+    protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
+            throws InvalidAlgorithmParameterException {
+        if (!mIvRequired) {
+            if (params != null) {
+                throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
+            }
+            return;
+        }
+
+        // IV is used
+        if (params == null) {
+            if (!mEncrypting) {
+                // IV must be provided by the caller
+                throw new InvalidAlgorithmParameterException(
+                        "IvParameterSpec must be provided when decrypting");
+            }
+            return;
+        }
+        if (!(params instanceof IvParameterSpec)) {
+            throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
+        }
+        mIv = ((IvParameterSpec) params).getIV();
+        if (mIv == null) {
+            throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
+        }
+    }
+
+    /**
+     * Invoked by {@code engineInit} to initialize algorithm-specific parameters. These parameters
+     * may need to be stored to be reused after {@code doFinal}.
+     *
+     * <p>The default implementation only handles the IV parameters.
+     *
+     * @param params algorithm parameters.
+     *
+     * @throws InvalidAlgorithmParameterException if some/all of the parameters cannot be
+     *         automatically configured and thus {@code Cipher.init} needs to be invoked with
+     *         explicitly provided parameters.
+     */
+    protected void initAlgorithmSpecificParameters(AlgorithmParameters params)
+            throws InvalidAlgorithmParameterException {
+        if (!mIvRequired) {
+            if (params != null) {
+                throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
+            }
+            return;
+        }
+
+        // IV is used
+        if (params == null) {
+            if (!mEncrypting) {
+                // IV must be provided by the caller
+                throw new InvalidAlgorithmParameterException("IV required when decrypting"
+                        + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
+            }
+            return;
+        }
+
+        IvParameterSpec ivSpec;
+        try {
+            ivSpec = params.getParameterSpec(IvParameterSpec.class);
+        } catch (InvalidParameterSpecException e) {
+            if (!mEncrypting) {
+                // IV must be provided by the caller
+                throw new InvalidAlgorithmParameterException("IV required when decrypting"
+                        + ", but not found in parameters: " + params, e);
+            }
+            mIv = null;
+            return;
+        }
+        mIv = ivSpec.getIV();
+        if (mIv == null) {
+            throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
+        }
+    }
+
+    /**
+     * Invoked by {@code engineInit} to initialize algorithm-specific parameters. These parameters
+     * may need to be stored to be reused after {@code doFinal}.
+     *
+     * <p>The default implementation only handles the IV parameter.
+     *
+     * @throws InvalidKeyException if some/all of the parameters cannot be automatically configured
+     *         and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters.
+     */
+    protected void initAlgorithmSpecificParameters() throws InvalidKeyException {
+        if (!mIvRequired) {
+            return;
+        }
+
+        // IV is used
+        if (!mEncrypting) {
+            throw new InvalidKeyException("IV required when decrypting"
+                    + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
+        }
+    }
+
+    /**
+     * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
+     *
+     * <p>The default implementation takes care of the IV.
+     *
+     * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
+     *        parameters.
+     */
+    protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) {
+        if (!mFirstOperationInitiated) {
+            // First begin operation -- see if we need to provide additional entropy for IV
+            // generation.
+            if (mIvRequired) {
+                // IV is needed
+                if ((mIv == null) && (mEncrypting)) {
+                    // TODO: Switch to keymaster-generated IV code below once keymaster supports
+                    // that.
+                    // IV is needed but was not provided by the caller -- generate an IV.
+                    mIv = new byte[mBlockSizeBytes];
+                    SecureRandom rng = (mRng != null) ? mRng : new SecureRandom();
+                    rng.nextBytes(mIv);
+//                    // IV was not provided by the caller and thus will be generated by keymaster.
+//                    // Mix in some additional entropy from the provided SecureRandom.
+//                    if (mRng != null) {
+//                        mAdditionalEntropyForBegin = new byte[mBlockSizeBytes];
+//                        mRng.nextBytes(mAdditionalEntropyForBegin);
+//                    }
+                }
+            }
+        }
+
+        if ((mIvRequired) && (mIv != null)) {
+            keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv);
+        }
+    }
+
+    /**
+     * Invoked by {@code engineInit} to obtain algorithm-specific parameters from the result of the
+     * Keymaster's {@code begin} operation. Some of these parameters may need to be reused after
+     * {@code doFinal} by {@link #addAlgorithmSpecificParametersToBegin(KeymasterArguments)}.
+     *
+     * <p>The default implementation only takes care of the IV.
+     *
+     * @param keymasterArgs keystore/keymaster arguments returned by KeyStore {@code begin}
+     *        operation.
+     */
+    protected void loadAlgorithmSpecificParametersFromBeginResult(
+            KeymasterArguments keymasterArgs) {
+        // NOTE: Keymaster doesn't always return an IV, even if it's used.
+        byte[] returnedIv = keymasterArgs.getBlob(KeymasterDefs.KM_TAG_NONCE, null);
+        if ((returnedIv != null) && (returnedIv.length == 0)) {
+            returnedIv = null;
+        }
+
+        if (mIvRequired) {
+            if (mIv == null) {
+                mIv = returnedIv;
+            } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
+                throw new CryptoOperationException("IV in use differs from provided IV");
+            }
+        } else {
+            if (returnedIv != null) {
+                throw new CryptoOperationException(
+                        "IV in use despite IV not being used by this transformation");
+            }
+        }
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreConnectException.java b/keystore/java/android/security/KeyStoreConnectException.java
index 4c465a4..8ed6e04 100644
--- a/keystore/java/android/security/KeyStoreConnectException.java
+++ b/keystore/java/android/security/KeyStoreConnectException.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 /**
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/keystore/java/android/security/KeyStoreCryptoOperation.java
similarity index 63%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to keystore/java/android/security/KeyStoreCryptoOperation.java
index c9fd989..19abd05 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/keystore/java/android/security/KeyStoreCryptoOperation.java
@@ -13,7 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package android.security;
+
+/**
+ * Cryptographic operation backed by {@link KeyStore}.
+ *
+ * @hide
+ */
+public interface KeyStoreCryptoOperation {
+    /**
+     * Gets the KeyStore operation handle of this crypto operation.
+     *
+     * @return handle or {@code null} if the KeyStore operation is not in progress.
+     */
+    Long getOperationHandle();
+}
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index a37ddce..1f8b7e4 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -1,5 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
+import android.os.IBinder;
 import android.security.keymaster.OperationResult;
 
 import java.io.ByteArrayOutputStream;
@@ -10,32 +27,36 @@
  * {@code update} and {@code finish} operations.
  *
  * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update and finish operations can consume only a
- * limited amount of data in one go because the operations are marshalled via Binder. Secondly, the
- * update operation may consume less data than provided, in which case the caller has to buffer
- * the remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
+ * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
+ * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
+ * operation may consume less data than provided, in which case the caller has to buffer the
+ * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
  * {@link #doFinal(byte[], int, int) doFinal} operations which can be used to conveniently implement
  * various JCA crypto primitives.
  *
- * <p>KeyStore operation through which data is streamed is abstracted away as
- * {@link KeyStoreOperation} to avoid having this class deal with operation tokens and occasional
- * additional parameters to update and final operations.
+ * <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
+ * a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
+ * parameters to {@code update} and {@code final} operations.
  *
  * @hide
  */
 public class KeyStoreCryptoOperationChunkedStreamer {
-    public interface KeyStoreOperation {
+
+    /**
+     * Bidirectional chunked data stream over a KeyStore crypto operation.
+     */
+    public interface Stream {
         /**
-         * Returns the result of the KeyStore update operation or null if keystore couldn't be
-         * reached.
+         * Returns the result of the KeyStore {@code update} operation or null if keystore couldn't
+         * be reached.
          */
         OperationResult update(byte[] input);
 
         /**
-         * Returns the result of the KeyStore finish operation or null if keystore couldn't be
-         * reached.
+         * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
+         * be reached.
          */
-        OperationResult finish(byte[] input);
+        OperationResult finish();
     }
 
     // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
@@ -43,23 +64,23 @@
     private static final int DEFAULT_MAX_CHUNK_SIZE = 64 * 1024;
     private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 
-    private final KeyStoreOperation mKeyStoreOperation;
+    private final Stream mKeyStoreStream;
     private final int mMaxChunkSize;
 
     private byte[] mBuffered = EMPTY_BYTE_ARRAY;
     private int mBufferedOffset;
     private int mBufferedLength;
 
-    public KeyStoreCryptoOperationChunkedStreamer(KeyStoreOperation operation) {
+    public KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
         this(operation, DEFAULT_MAX_CHUNK_SIZE);
     }
 
-    public KeyStoreCryptoOperationChunkedStreamer(KeyStoreOperation operation, int maxChunkSize) {
-        mKeyStoreOperation = operation;
+    public KeyStoreCryptoOperationChunkedStreamer(Stream operation, int maxChunkSize) {
+        mKeyStoreStream = operation;
         mMaxChunkSize = maxChunkSize;
     }
 
-    public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeymasterException {
+    public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException {
         if (inputLength == 0) {
             // No input provided
             return EMPTY_BYTE_ARRAY;
@@ -73,10 +94,9 @@
             if ((mBufferedLength + inputLength) > mMaxChunkSize) {
                 // Too much input for one chunk -- extract one max-sized chunk and feed it into the
                 // update operation.
-                chunk = new byte[mMaxChunkSize];
-                System.arraycopy(mBuffered, mBufferedOffset, chunk, 0, mBufferedLength);
-                inputBytesInChunk = chunk.length - mBufferedLength;
-                System.arraycopy(input, inputOffset, chunk, mBufferedLength, inputBytesInChunk);
+                inputBytesInChunk = mMaxChunkSize - mBufferedLength;
+                chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+                        input, inputOffset, inputBytesInChunk);
             } else {
                 // All of available input fits into one chunk.
                 if ((mBufferedLength == 0) && (inputOffset == 0)
@@ -87,21 +107,20 @@
                     inputBytesInChunk = input.length;
                 } else {
                     // Need to combine buffered data with input data into one array.
-                    chunk = new byte[mBufferedLength + inputLength];
                     inputBytesInChunk = inputLength;
-                    System.arraycopy(mBuffered, mBufferedOffset, chunk, 0, mBufferedLength);
-                    System.arraycopy(input, inputOffset, chunk, mBufferedLength, inputLength);
+                    chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+                            input, inputOffset, inputBytesInChunk);
                 }
             }
             // Update input array references to reflect that some of its bytes are now in mBuffered.
             inputOffset += inputBytesInChunk;
             inputLength -= inputBytesInChunk;
 
-            OperationResult opResult = mKeyStoreOperation.update(chunk);
+            OperationResult opResult = mKeyStoreStream.update(chunk);
             if (opResult == null) {
                 throw new KeyStoreConnectException();
             } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-                throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
+                throw KeyStore.getKeyStoreException(opResult.resultCode);
             }
 
             if (opResult.inputConsumed == chunk.length) {
@@ -169,60 +188,122 @@
     }
 
     public byte[] doFinal(byte[] input, int inputOffset, int inputLength)
-            throws KeymasterException {
+            throws KeyStoreException {
         if (inputLength == 0) {
             // No input provided -- simplify the rest of the code
             input = EMPTY_BYTE_ARRAY;
             inputOffset = 0;
         }
 
-        byte[] updateOutput = null;
-        if ((mBufferedLength + inputLength) > mMaxChunkSize) {
-            updateOutput = update(input, inputOffset, inputLength);
-            inputOffset += inputLength;
-            inputLength = 0;
-        }
-        // All of available input fits into one chunk.
+        // Flush all buffered input and provided input into keystore/keymaster.
+        byte[] output = update(input, inputOffset, inputLength);
+        output = concat(output, flush());
 
-        byte[] finalChunk;
-        if ((mBufferedLength == 0) && (inputOffset == 0)
-                && (inputLength == input.length)) {
-            // Nothing buffered and all of input array needs to be fed into the finish operation.
-            finalChunk = input;
-        } else {
-            // Need to combine buffered data with input data into one array.
-            finalChunk = new byte[mBufferedLength + inputLength];
-            System.arraycopy(mBuffered, mBufferedOffset, finalChunk, 0, mBufferedLength);
-            System.arraycopy(input, inputOffset, finalChunk, mBufferedLength, inputLength);
+        OperationResult opResult = mKeyStoreStream.finish();
+        if (opResult == null) {
+            throw new KeyStoreConnectException();
+        } else if (opResult.resultCode != KeyStore.NO_ERROR) {
+            throw KeyStore.getKeyStoreException(opResult.resultCode);
         }
+
+        return concat(output, opResult.output);
+    }
+
+    /**
+     * Passes all of buffered input into the the KeyStore operation (via the {@code update}
+     * operation) and returns output.
+     */
+    public byte[] flush() throws KeyStoreException {
+        if (mBufferedLength <= 0) {
+            return EMPTY_BYTE_ARRAY;
+        }
+
+        byte[] chunk = subarray(mBuffered, mBufferedOffset, mBufferedLength);
         mBuffered = EMPTY_BYTE_ARRAY;
         mBufferedLength = 0;
         mBufferedOffset = 0;
 
-        OperationResult opResult = mKeyStoreOperation.finish(finalChunk);
+        OperationResult opResult = mKeyStoreStream.update(chunk);
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode);
+            throw KeyStore.getKeyStoreException(opResult.resultCode);
         }
 
-        if (opResult.inputConsumed != finalChunk.length) {
-            throw new CryptoOperationException("Unexpected number of bytes consumed by finish: "
-                    + opResult.inputConsumed + " instead of " + finalChunk.length);
+        if (opResult.inputConsumed < chunk.length) {
+            throw new CryptoOperationException("Keystore failed to consume all input. Provided: "
+                    + chunk.length + ", consumed: " + opResult.inputConsumed);
+        } else if (opResult.inputConsumed > chunk.length) {
+            throw new CryptoOperationException("Keystore consumed more input than provided"
+                    + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
         }
 
-        // Return the concatenation of the output of update and finish.
-        byte[] result;
-        byte[] finishOutput = opResult.output;
-        if ((updateOutput == null) || (updateOutput.length == 0)) {
-            result = finishOutput;
-        } else if ((finishOutput == null) || (finishOutput.length == 0)) {
-            result = updateOutput;
+        return (opResult.output != null) ? opResult.output : EMPTY_BYTE_ARRAY;
+    }
+
+    private static byte[] concat(byte[] arr1, byte[] arr2) {
+        if ((arr1 == null) || (arr1.length == 0)) {
+            return arr2;
+        } else if ((arr2 == null) || (arr2.length == 0)) {
+            return arr1;
         } else {
-            result = new byte[updateOutput.length + finishOutput.length];
-            System.arraycopy(updateOutput, 0, result, 0, updateOutput.length);
-            System.arraycopy(finishOutput, 0, result, updateOutput.length, finishOutput.length);
+            byte[] result = new byte[arr1.length + arr2.length];
+            System.arraycopy(arr1, 0, result, 0, arr1.length);
+            System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
+            return result;
         }
-        return (result != null) ? result : EMPTY_BYTE_ARRAY;
+    }
+
+    private static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
+            int len2) {
+        if (len1 == 0) {
+            return subarray(arr2, offset2, len2);
+        } else if (len2 == 0) {
+            return subarray(arr1, offset1, len1);
+        } else {
+            byte[] result = new byte[len1 + len2];
+            System.arraycopy(arr1, offset1, result, 0, len1);
+            System.arraycopy(arr2, offset2, result, len1, len2);
+            return result;
+        }
+    }
+
+    private static byte[] subarray(byte[] arr, int offset, int len) {
+        if (len == 0) {
+            return EMPTY_BYTE_ARRAY;
+        }
+        if ((offset == 0) && (len == arr.length)) {
+            return arr;
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(arr, offset, result, 0, len);
+        return result;
+    }
+
+    /**
+     * Main data stream via a KeyStore streaming operation.
+     *
+     * <p>For example, for an encryption operation, this is the stream through which plaintext is
+     * provided and ciphertext is obtained.
+     */
+    public static class MainDataStream implements Stream {
+
+        private final KeyStore mKeyStore;
+        private final IBinder mOperationToken;
+
+        public MainDataStream(KeyStore keyStore, IBinder operationToken) {
+            mKeyStore = keyStore;
+            mOperationToken = operationToken;
+        }
+
+        @Override
+        public OperationResult update(byte[] input) {
+            return mKeyStore.update(mOperationToken, null, input);
+        }
+
+        @Override
+        public OperationResult finish() {
+            return mKeyStore.finish(mOperationToken, null, null);
+        }
     }
 }
diff --git a/keystore/java/android/security/KeyStoreException.java b/keystore/java/android/security/KeyStoreException.java
new file mode 100644
index 0000000..88e768c
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * KeyStore/keymaster exception with positive error codes coming from the KeyStore and negative
+ * ones from keymaster.
+ *
+ * @hide
+ */
+public class KeyStoreException extends Exception {
+
+    private final int mErrorCode;
+
+    public KeyStoreException(int errorCode, String message) {
+        super(message);
+        mErrorCode = errorCode;
+    }
+
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index 3080d7b..f69e7d1 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 import android.os.IBinder;
@@ -17,11 +33,35 @@
  *
  * @hide
  */
-public abstract class KeyStoreHmacSpi extends MacSpi {
+public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
+
+    public static class HmacSHA1 extends KeyStoreHmacSpi {
+        public HmacSHA1() {
+            super(KeyStoreKeyConstraints.Digest.SHA1);
+        }
+    }
+
+    public static class HmacSHA224 extends KeyStoreHmacSpi {
+        public HmacSHA224() {
+            super(KeyStoreKeyConstraints.Digest.SHA224);
+        }
+    }
 
     public static class HmacSHA256 extends KeyStoreHmacSpi {
         public HmacSHA256() {
-            super(KeyStoreKeyConstraints.Digest.SHA256, 256 / 8);
+            super(KeyStoreKeyConstraints.Digest.SHA256);
+        }
+    }
+
+    public static class HmacSHA384 extends KeyStoreHmacSpi {
+        public HmacSHA384() {
+            super(KeyStoreKeyConstraints.Digest.SHA384);
+        }
+    }
+
+    public static class HmacSHA512 extends KeyStoreHmacSpi {
+        public HmacSHA512() {
+            super(KeyStoreKeyConstraints.Digest.SHA512);
         }
     }
 
@@ -34,10 +74,11 @@
     // The fields below are reset by the engineReset operation.
     private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
     private IBinder mOperationToken;
+    private Long mOperationHandle;
 
-    protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest, int macSizeBytes) {
+    protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest) {
         mDigest = digest;
-        mMacSizeBytes = macSizeBytes;
+        mMacSizeBytes = KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
     }
 
     @Override
@@ -61,7 +102,11 @@
         }
 
         mKeyAliasInKeyStore = ((KeyStoreSecretKey) key).getAlias();
+        if (mKeyAliasInKeyStore == null) {
+            throw new InvalidKeyException("Key's KeyStore alias not known");
+        }
         engineReset();
+        ensureKeystoreOperationInitialized();
     }
 
     @Override
@@ -71,9 +116,20 @@
             mOperationToken = null;
             mKeyStore.abort(operationToken);
         }
+        mOperationHandle = null;
         mChunkedStreamer = null;
+    }
+
+    private void ensureKeystoreOperationInitialized() {
+        if (mChunkedStreamer != null) {
+            return;
+        }
+        if (mKeyAliasInKeyStore == null) {
+            throw new IllegalStateException("Not initialized");
+        }
 
         KeymasterArguments keymasterArgs = new KeymasterArguments();
+        keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.HMAC);
         keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mDigest);
 
         OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
@@ -85,15 +141,16 @@
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw new CryptoOperationException("Failed to start keystore operation",
-                    KeymasterUtils.getExceptionForKeymasterError(opResult.resultCode));
+            throw KeyStore.getCryptoOperationException(opResult.resultCode);
         }
-        mOperationToken = opResult.token;
-        if (mOperationToken == null) {
+        if (opResult.token == null) {
             throw new CryptoOperationException("Keystore returned null operation token");
         }
+        mOperationToken = opResult.token;
+        mOperationHandle = opResult.operationHandle;
         mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
-                new KeyStoreStreamingConsumer(mKeyStore, mOperationToken));
+                new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
+                        mKeyStore, mOperationToken));
     }
 
     @Override
@@ -103,15 +160,13 @@
 
     @Override
     protected void engineUpdate(byte[] input, int offset, int len) {
-        if (mChunkedStreamer == null) {
-            throw new IllegalStateException("Not initialized");
-        }
+        ensureKeystoreOperationInitialized();
 
         byte[] output;
         try {
             output = mChunkedStreamer.update(input, offset, len);
-        } catch (KeymasterException e) {
-            throw new CryptoOperationException("Keystore operation failed", e);
+        } catch (KeyStoreException e) {
+            throw KeyStore.getCryptoOperationException(e);
         }
         if ((output != null) && (output.length != 0)) {
             throw new CryptoOperationException("Update operation unexpectedly produced output");
@@ -120,15 +175,13 @@
 
     @Override
     protected byte[] engineDoFinal() {
-        if (mChunkedStreamer == null) {
-            throw new IllegalStateException("Not initialized");
-        }
+        ensureKeystoreOperationInitialized();
 
         byte[] result;
         try {
             result = mChunkedStreamer.doFinal(null, 0, 0);
-        } catch (KeymasterException e) {
-            throw new CryptoOperationException("Keystore operation failed", e);
+        } catch (KeyStoreException e) {
+            throw KeyStore.getCryptoOperationException(e);
         }
 
         engineReset();
@@ -140,7 +193,6 @@
         try {
             IBinder operationToken = mOperationToken;
             if (operationToken != null) {
-                mOperationToken = null;
                 mKeyStore.abort(operationToken);
             }
         } finally {
@@ -148,27 +200,8 @@
         }
     }
 
-    /**
-     * KeyStore-backed consumer of {@code MacSpi}'s chunked stream.
-     */
-    private static class KeyStoreStreamingConsumer
-            implements KeyStoreCryptoOperationChunkedStreamer.KeyStoreOperation {
-        private final KeyStore mKeyStore;
-        private final IBinder mOperationToken;
-
-        private KeyStoreStreamingConsumer(KeyStore keyStore, IBinder operationToken) {
-            mKeyStore = keyStore;
-            mOperationToken = operationToken;
-        }
-
-        @Override
-        public OperationResult update(byte[] input) {
-            return mKeyStore.update(mOperationToken, null, input);
-        }
-
-        @Override
-        public OperationResult finish(byte[] input) {
-            return mKeyStore.finish(mOperationToken, null, input);
-        }
+    @Override
+    public Long getOperationHandle() {
+        return mOperationHandle;
     }
 }
diff --git a/keystore/java/android/security/KeyStoreKeyCharacteristics.java b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
new file mode 100644
index 0000000..1f5d400
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.IntDef;
+import android.security.keymaster.KeymasterDefs;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Characteristics of {@code AndroidKeyStore} keys.
+ *
+ * @hide
+ */
+public abstract class KeyStoreKeyCharacteristics {
+    private KeyStoreKeyCharacteristics() {}
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({Origin.GENERATED, Origin.IMPORTED})
+    public @interface OriginEnum {}
+
+    /**
+     * Origin of the key.
+     */
+    public static abstract class Origin {
+        private Origin() {}
+
+        /** Key was generated inside AndroidKeyStore. */
+        public static final int GENERATED = 1 << 0;
+
+        /** Key was imported into AndroidKeyStore. */
+        public static final int IMPORTED = 1 << 1;
+
+        /**
+         * @hide
+         */
+        public static @OriginEnum int fromKeymaster(int origin) {
+            switch (origin) {
+                case KeymasterDefs.KM_ORIGIN_HARDWARE:
+                    return GENERATED;
+                case KeymasterDefs.KM_ORIGIN_IMPORTED:
+                    return IMPORTED;
+                default:
+                    throw new IllegalArgumentException("Unknown origin: " + origin);
+            }
+        }
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
index b5e2436..98ac3e7 100644
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ b/keystore/java/android/security/KeyStoreKeyConstraints.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 import android.annotation.IntDef;
@@ -5,7 +21,6 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Locale;
 
@@ -18,7 +33,8 @@
     private KeyStoreKeyConstraints() {}
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag=true, value={Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
+    @IntDef(flag = true,
+            value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
     public @interface PurposeEnum {}
 
     /**
@@ -48,11 +64,6 @@
         public static final int VERIFY = 1 << 3;
 
         /**
-         * Number of flags defined above. Needs to be kept in sync with the flags above.
-         */
-        private static final int VALUE_COUNT = 4;
-
-        /**
          * @hide
          */
         public static int toKeymaster(@PurposeEnum int purpose) {
@@ -91,22 +102,12 @@
         /**
          * @hide
          */
-        public static int[] allToKeymaster(int purposes) {
-            int[] result = new int[VALUE_COUNT];
-            int resultCount = 0;
-            int purpose = 1;
-            for (int i = 0; i < 32; i++) {
-                if ((purposes & 1) != 0) {
-                    result[resultCount] = toKeymaster(purpose);
-                    resultCount++;
-                }
-                purposes >>>= 1;
-                purpose <<= 1;
-                if (purposes == 0) {
-                    break;
-                }
+        public static int[] allToKeymaster(@PurposeEnum int purposes) {
+            int[] result = getSetFlags(purposes);
+            for (int i = 0; i < result.length; i++) {
+                result[i] = toKeymaster(result[i]);
             }
-            return Arrays.copyOf(result, resultCount);
+            return result;
         }
 
         /**
@@ -122,7 +123,7 @@
     }
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Algorithm.AES, Algorithm.HMAC})
+    @IntDef({Algorithm.AES, Algorithm.HMAC, Algorithm.RSA, Algorithm.EC})
     public @interface AlgorithmEnum {}
 
     /**
@@ -134,12 +135,22 @@
         /**
          * Key algorithm: AES.
          */
-        public static final int AES = 0;
+        public static final int AES = 1 << 0;
 
         /**
          * Key algorithm: HMAC.
          */
-        public static final int HMAC = 1;
+        public static final int HMAC = 1 << 1;
+
+        /**
+         * Key algorithm: RSA.
+         */
+        public static final int RSA = 1 << 2;
+
+        /**
+         * Key algorithm: EC.
+         */
+        public static final int EC = 1 << 3;
 
         /**
          * @hide
@@ -150,6 +161,10 @@
                     return KeymasterDefs.KM_ALGORITHM_AES;
                 case HMAC:
                     return KeymasterDefs.KM_ALGORITHM_HMAC;
+                case RSA:
+                    return KeymasterDefs.KM_ALGORITHM_RSA;
+                case EC:
+                    return KeymasterDefs.KM_ALGORITHM_EC;
                 default:
                     throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
             }
@@ -164,6 +179,10 @@
                     return AES;
                 case KeymasterDefs.KM_ALGORITHM_HMAC:
                     return HMAC;
+                case KeymasterDefs.KM_ALGORITHM_RSA:
+                    return RSA;
+                case KeymasterDefs.KM_ALGORITHM_EC:
+                    return EC;
                 default:
                     throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
             }
@@ -178,6 +197,10 @@
                     return "AES";
                 case HMAC:
                     return "HMAC";
+                case RSA:
+                    return "RSA";
+                case EC:
+                    return "EC";
                 default:
                     throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
             }
@@ -212,8 +235,18 @@
                         throw new IllegalArgumentException("HMAC digest not specified");
                     }
                     switch (digest) {
+                        case Digest.MD5:
+                            return "HmacMD5";
+                        case Digest.SHA1:
+                            return "HmacSHA1";
+                        case Digest.SHA224:
+                            return "HmacSHA224";
                         case Digest.SHA256:
                             return "HmacSHA256";
+                        case Digest.SHA384:
+                            return "HmacSHA384";
+                        case Digest.SHA512:
+                            return "HmacSHA512";
                         default:
                             throw new IllegalArgumentException(
                                     "Unsupported HMAC digest: " + digest);
@@ -228,6 +261,10 @@
          */
         public static String toJCAKeyPairAlgorithm(@AlgorithmEnum int algorithm) {
             switch (algorithm) {
+                case RSA:
+                    return "RSA";
+                case EC:
+                    return "EC";
                 default:
                     throw new IllegalArgumentException("Unsupported key alorithm: " + algorithm);
             }
@@ -235,7 +272,15 @@
     }
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Padding.NONE, Padding.ZERO, Padding.PKCS7})
+    @IntDef(flag = true,
+            value = {
+                Padding.NONE,
+                Padding.PKCS7,
+                Padding.RSA_PKCS1_ENCRYPTION,
+                Padding.RSA_PKCS1_SIGNATURE,
+                Padding.RSA_OAEP,
+                Padding.RSA_PSS,
+                })
     public @interface PaddingEnum {}
 
     /**
@@ -247,17 +292,32 @@
         /**
          * No padding.
          */
-        public static final int NONE = 0;
-
-        /**
-         * Pad with zeros.
-         */
-        public static final int ZERO = 1;
+        public static final int NONE = 1 << 0;
 
         /**
          * PKCS#7 padding.
          */
-        public static final int PKCS7 = 2;
+        public static final int PKCS7 = 1 << 1;
+
+        /**
+         * RSA PKCS#1 v1.5 padding for encryption/decryption.
+         */
+        public static final int RSA_PKCS1_ENCRYPTION = 1 << 2;
+
+        /**
+         * RSA PKCS#1 v1.5 padding for signatures.
+         */
+        public static final int RSA_PKCS1_SIGNATURE = 1 << 3;
+
+        /**
+         * RSA Optimal Asymmetric Encryption Padding (OAEP).
+         */
+        public static final int RSA_OAEP = 1 << 4;
+
+        /**
+         * RSA PKCS#1 v2.1 Probabilistic Signature Scheme (PSS) padding.
+         */
+        public static final int RSA_PSS = 1 << 5;
 
         /**
          * @hide
@@ -266,10 +326,16 @@
             switch (padding) {
                 case NONE:
                     return KeymasterDefs.KM_PAD_NONE;
-                case ZERO:
-                    return KeymasterDefs.KM_PAD_ZERO;
                 case PKCS7:
                     return KeymasterDefs.KM_PAD_PKCS7;
+                case RSA_PKCS1_ENCRYPTION:
+                    return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+                case RSA_PKCS1_SIGNATURE:
+                    return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
+                case RSA_OAEP:
+                    return KeymasterDefs.KM_PAD_RSA_OAEP;
+                case RSA_PSS:
+                    return KeymasterDefs.KM_PAD_RSA_PSS;
                 default:
                     throw new IllegalArgumentException("Unknown padding: " + padding);
             }
@@ -282,10 +348,16 @@
             switch (padding) {
                 case KeymasterDefs.KM_PAD_NONE:
                     return NONE;
-                case KeymasterDefs.KM_PAD_ZERO:
-                    return ZERO;
                 case KeymasterDefs.KM_PAD_PKCS7:
                     return PKCS7;
+                case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+                    return RSA_PKCS1_ENCRYPTION;
+                case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
+                    return RSA_PKCS1_SIGNATURE;
+                case KeymasterDefs.KM_PAD_RSA_OAEP:
+                    return RSA_OAEP;
+                case KeymasterDefs.KM_PAD_RSA_PSS:
+                    return RSA_PSS;
                 default:
                     throw new IllegalArgumentException("Unknown padding: " + padding);
             }
@@ -298,18 +370,75 @@
             switch (padding) {
                 case NONE:
                     return "NONE";
-                case ZERO:
-                    return "ZERO";
                 case PKCS7:
                     return "PKCS#7";
+                case RSA_PKCS1_ENCRYPTION:
+                    return "RSA PKCS#1 (encryption)";
+                case RSA_PKCS1_SIGNATURE:
+                    return "RSA PKCS#1 (signature)";
+                case RSA_OAEP:
+                    return "RSA OAEP";
+                case RSA_PSS:
+                    return "RSA PSS";
                 default:
                     throw new IllegalArgumentException("Unknown padding: " + padding);
             }
         }
+
+        /**
+         * @hide
+         */
+        public static @PaddingEnum int fromJCACipherPadding(String padding) {
+            String paddingLower = padding.toLowerCase(Locale.US);
+            if ("nopadding".equals(paddingLower)) {
+                return NONE;
+            } else if ("pkcs7padding".equals(paddingLower)) {
+                return PKCS7;
+            } else if ("pkcs1padding".equals(paddingLower)) {
+                return RSA_PKCS1_ENCRYPTION;
+            } else if (("oaeppadding".equals(paddingLower))
+                    || ((paddingLower.startsWith("oaepwith"))
+                            && (paddingLower.endsWith("padding")))) {
+                return RSA_OAEP;
+            } else {
+                throw new IllegalArgumentException("Unknown padding: " + padding);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int[] allToKeymaster(@PaddingEnum int paddings) {
+            int[] result = getSetFlags(paddings);
+            for (int i = 0; i < result.length; i++) {
+                result[i] = toKeymaster(result[i]);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @PaddingEnum int allFromKeymaster(Collection<Integer> paddings) {
+            @PaddingEnum int result = 0;
+            for (int keymasterPadding : paddings) {
+                result |= fromKeymaster(keymasterPadding);
+            }
+            return result;
+        }
     }
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({Digest.NONE, Digest.SHA256})
+    @IntDef(flag = true,
+            value = {
+                Digest.NONE,
+                Digest.MD5,
+                Digest.SHA1,
+                Digest.SHA224,
+                Digest.SHA256,
+                Digest.SHA384,
+                Digest.SHA512,
+                })
     public @interface DigestEnum {}
 
     /**
@@ -322,12 +451,37 @@
         /**
          * No digest: sign/authenticate the raw message.
          */
-        public static final int NONE = 0;
+        public static final int NONE = 1 << 0;
 
         /**
-         * SHA-256 digest.
+         * MD5 digest.
          */
-        public static final int SHA256 = 1;
+        public static final int MD5 = 1 << 1;
+
+        /**
+         * SHA-1 digest.
+         */
+        public static final int SHA1 = 1 << 2;
+
+        /**
+         * SHA-2 224 (aka SHA-224) digest.
+         */
+        public static final int SHA224 = 1 << 3;
+
+        /**
+         * SHA-2 256 (aka SHA-256) digest.
+         */
+        public static final int SHA256 = 1 << 4;
+
+        /**
+         * SHA-2 384 (aka SHA-384) digest.
+         */
+        public static final int SHA384 = 1 << 5;
+
+        /**
+         * SHA-2 512 (aka SHA-512) digest.
+         */
+        public static final int SHA512 = 1 << 6;
 
         /**
          * @hide
@@ -336,8 +490,18 @@
             switch (digest) {
                 case NONE:
                     return "NONE";
+                case MD5:
+                    return "MD5";
+                case SHA1:
+                    return "SHA-1";
+                case SHA224:
+                    return "SHA-224";
                 case SHA256:
-                    return "SHA256";
+                    return "SHA-256";
+                case SHA384:
+                    return "SHA-384";
+                case SHA512:
+                    return "SHA-512";
                 default:
                     throw new IllegalArgumentException("Unknown digest: " + digest);
             }
@@ -346,12 +510,40 @@
         /**
          * @hide
          */
+        public static String allToString(@DigestEnum int digests) {
+            StringBuilder result = new StringBuilder("[");
+            boolean firstValue = true;
+            for (@DigestEnum int digest : getSetFlags(digests)) {
+                if (firstValue) {
+                    firstValue = false;
+                } else {
+                    result.append(", ");
+                }
+                result.append(toString(digest));
+            }
+            result.append(']');
+            return result.toString();
+        }
+
+        /**
+         * @hide
+         */
         public static int toKeymaster(@DigestEnum int digest) {
             switch (digest) {
                 case NONE:
                     return KeymasterDefs.KM_DIGEST_NONE;
+                case MD5:
+                    return KeymasterDefs.KM_DIGEST_MD5;
+                case SHA1:
+                    return KeymasterDefs.KM_DIGEST_SHA1;
+                case SHA224:
+                    return KeymasterDefs.KM_DIGEST_SHA_2_224;
                 case SHA256:
                     return KeymasterDefs.KM_DIGEST_SHA_2_256;
+                case SHA384:
+                    return KeymasterDefs.KM_DIGEST_SHA_2_384;
+                case SHA512:
+                    return KeymasterDefs.KM_DIGEST_SHA_2_512;
                 default:
                     throw new IllegalArgumentException("Unknown digest: " + digest);
             }
@@ -364,8 +556,18 @@
             switch (digest) {
                 case KeymasterDefs.KM_DIGEST_NONE:
                     return NONE;
+                case KeymasterDefs.KM_DIGEST_MD5:
+                    return MD5;
+                case KeymasterDefs.KM_DIGEST_SHA1:
+                    return SHA1;
+                case KeymasterDefs.KM_DIGEST_SHA_2_224:
+                    return SHA224;
                 case KeymasterDefs.KM_DIGEST_SHA_2_256:
                     return SHA256;
+                case KeymasterDefs.KM_DIGEST_SHA_2_384:
+                    return SHA384;
+                case KeymasterDefs.KM_DIGEST_SHA_2_512:
+                    return SHA512;
                 default:
                     throw new IllegalArgumentException("Unknown digest: " + digest);
             }
@@ -374,14 +576,46 @@
         /**
          * @hide
          */
+        public static int[] allToKeymaster(@DigestEnum int digests) {
+            int[] result = getSetFlags(digests);
+            for (int i = 0; i < result.length; i++) {
+                result[i] = toKeymaster(result[i]);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @DigestEnum int allFromKeymaster(Collection<Integer> digests) {
+            @DigestEnum int result = 0;
+            for (int keymasterDigest : digests) {
+                result |= fromKeymaster(keymasterDigest);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
         public static @DigestEnum Integer fromJCASecretKeyAlgorithm(String algorithm) {
             String algorithmLower = algorithm.toLowerCase(Locale.US);
             if (algorithmLower.startsWith("hmac")) {
-                if ("hmacsha256".equals(algorithmLower)) {
+                String digestLower = algorithmLower.substring("hmac".length());
+                if ("md5".equals(digestLower)) {
+                    return MD5;
+                } else if ("sha1".equals(digestLower)) {
+                    return SHA1;
+                } else if ("sha224".equals(digestLower)) {
+                    return SHA224;
+                } else if ("sha256".equals(digestLower)) {
                     return SHA256;
+                } else if ("sha384".equals(digestLower)) {
+                    return SHA384;
+                } else if ("sha512".equals(digestLower)) {
+                    return SHA512;
                 } else {
-                    throw new IllegalArgumentException("Unsupported digest: "
-                            + algorithmLower.substring("hmac".length()));
+                    throw new IllegalArgumentException("Unsupported digest: " + digestLower);
                 }
             } else {
                 return null;
@@ -395,8 +629,18 @@
             switch (digest) {
                 case NONE:
                     return "NONE";
+                case MD5:
+                    return "MD5";
+                case SHA1:
+                    return "SHA1";
+                case SHA224:
+                    return "SHA224";
                 case SHA256:
                     return "SHA256";
+                case SHA384:
+                    return "SHA384";
+                case SHA512:
+                    return "SHA512";
                 default:
                     throw new IllegalArgumentException("Unknown digest: " + digest);
             }
@@ -409,8 +653,18 @@
             switch (digest) {
                 case NONE:
                     return null;
+                case MD5:
+                    return 128 / 8;
+                case SHA1:
+                    return 160 / 8;
+                case SHA224:
+                    return 224 / 8;
                 case SHA256:
                     return 256 / 8;
+                case SHA384:
+                    return 384 / 8;
+                case SHA512:
+                    return 512 / 8;
                 default:
                     throw new IllegalArgumentException("Unknown digest: " + digest);
             }
@@ -418,7 +672,8 @@
     }
 
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({BlockMode.ECB})
+    @IntDef(flag = true,
+            value = {BlockMode.ECB, BlockMode.CBC, BlockMode.CTR, BlockMode.GCM})
     public @interface BlockModeEnum {}
 
     /**
@@ -427,10 +682,25 @@
     public static abstract class BlockMode {
         private BlockMode() {}
 
+        /** Electronic Codebook (ECB) block mode. */
+        public static final int ECB = 1 << 0;
+
+        /** Cipher Block Chaining (CBC) block mode. */
+        public static final int CBC = 1 << 1;
+
+        /** Counter (CTR) block mode. */
+        public static final int CTR = 1 << 2;
+
+        /** Galois/Counter Mode (GCM) block mode. */
+        public static final int GCM = 1 << 3;
+
         /**
-         * Electronic Codebook (ECB) block mode.
+         * Set of block modes compatible with IND-CPA if used correctly.
+         *
+         * @hide
          */
-        public static final int ECB = 0;
+        public static final @BlockModeEnum int IND_CPA_COMPATIBLE_MODES =
+                CBC | CTR | GCM;
 
         /**
          * @hide
@@ -439,6 +709,12 @@
             switch (mode) {
                 case ECB:
                     return KeymasterDefs.KM_MODE_ECB;
+                case CBC:
+                    return KeymasterDefs.KM_MODE_CBC;
+                case CTR:
+                    return KeymasterDefs.KM_MODE_CTR;
+                case GCM:
+                    return KeymasterDefs.KM_MODE_GCM;
                 default:
                     throw new IllegalArgumentException("Unknown block mode: " + mode);
             }
@@ -451,6 +727,12 @@
             switch (mode) {
                 case KeymasterDefs.KM_MODE_ECB:
                     return ECB;
+                case KeymasterDefs.KM_MODE_CBC:
+                    return CBC;
+                case KeymasterDefs.KM_MODE_CTR:
+                    return CTR;
+                case KeymasterDefs.KM_MODE_GCM:
+                    return GCM;
                 default:
                     throw new IllegalArgumentException("Unknown block mode: " + mode);
             }
@@ -459,13 +741,206 @@
         /**
          * @hide
          */
+        public static int[] allToKeymaster(@BlockModeEnum int modes) {
+            int[] result = getSetFlags(modes);
+            for (int i = 0; i < result.length; i++) {
+                result[i] = toKeymaster(result[i]);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @BlockModeEnum int allFromKeymaster(Collection<Integer> modes) {
+            @BlockModeEnum int result = 0;
+            for (int keymasterMode : modes) {
+                result |= fromKeymaster(keymasterMode);
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
         public static String toString(@BlockModeEnum int mode) {
             switch (mode) {
                 case ECB:
                     return "ECB";
+                case CBC:
+                    return "CBC";
+                case CTR:
+                    return "CTR";
+                case GCM:
+                    return "GCM";
                 default:
                     throw new IllegalArgumentException("Unknown block mode: " + mode);
             }
         }
+
+        /**
+         * @hide
+         */
+        public static String allToString(@BlockModeEnum int modes) {
+            StringBuilder result = new StringBuilder("[");
+            boolean firstValue = true;
+            for (@BlockModeEnum int mode : getSetFlags(modes)) {
+                if (firstValue) {
+                    firstValue = false;
+                } else {
+                    result.append(", ");
+                }
+                result.append(toString(mode));
+            }
+            result.append(']');
+            return result.toString();
+        }
+
+        /**
+         * @hide
+         */
+        public static @BlockModeEnum int fromJCAMode(String mode) {
+            String modeLower = mode.toLowerCase(Locale.US);
+            if ("ecb".equals(modeLower)) {
+                return ECB;
+            } else if ("cbc".equals(modeLower)) {
+                return CBC;
+            } else if ("ctr".equals(modeLower)) {
+                return CTR;
+            } else if ("gcm".equals(modeLower)) {
+                return GCM;
+            } else {
+                throw new IllegalArgumentException("Unknown block mode: " + mode);
+            }
+        }
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = {UserAuthenticator.LOCK_SCREEN})
+    public @interface UserAuthenticatorEnum {}
+
+    /**
+     * User authenticators which can be used to restrict/protect access to keys.
+     */
+    public static abstract class UserAuthenticator {
+        private UserAuthenticator() {}
+
+        /** Lock screen. */
+        public static final int LOCK_SCREEN = 1 << 0;
+
+        /** Fingerprint reader/sensor. */
+        public static final int FINGERPRINT_READER = 1 << 1;
+
+        /**
+         * @hide
+         */
+        public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return KeymasterDefs.HW_AUTH_PASSWORD;
+                case FINGERPRINT_READER:
+                    return KeymasterDefs.HW_AUTH_FINGERPRINT;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
+            switch (userAuthenticator) {
+                case KeymasterDefs.HW_AUTH_PASSWORD:
+                    return LOCK_SCREEN;
+                case FINGERPRINT_READER:
+                    return FINGERPRINT_READER;
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+
+        /**
+         * @hide
+         */
+        public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
+            int result = 0;
+            int userAuthenticator = 1;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    result |= toKeymaster(userAuthenticator);
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
+            @UserAuthenticatorEnum int result = 0;
+            int userAuthenticator = 1;
+            while (userAuthenticators != 0) {
+                if ((userAuthenticators & 1) != 0) {
+                    result |= fromKeymaster(userAuthenticator);
+                }
+                userAuthenticators >>>= 1;
+                userAuthenticator <<= 1;
+            }
+            return result;
+        }
+
+        /**
+         * @hide
+         */
+        public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
+            switch (userAuthenticator) {
+                case LOCK_SCREEN:
+                    return "LOCK_SCREEN";
+                case FINGERPRINT_READER:
+                    return "FINGERPRINT_READER";
+                default:
+                    throw new IllegalArgumentException(
+                            "Unknown user authenticator: " + userAuthenticator);
+            }
+        }
+    }
+
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+    private static int[] getSetFlags(int flags) {
+        if (flags == 0) {
+            return EMPTY_INT_ARRAY;
+        }
+        int result[] = new int[getSetBitCount(flags)];
+        int resultOffset = 0;
+        int flag = 1;
+        while (flags != 0) {
+            if ((flags & 1) != 0) {
+                result[resultOffset] = flag;
+                resultOffset++;
+            }
+            flags >>>= 1;
+            flag <<= 1;
+        }
+        return result;
+    }
+
+    private static int getSetBitCount(int value) {
+        if (value == 0) {
+            return 0;
+        }
+        int result = 0;
+        while (value != 0) {
+            if ((value & 1) != 0) {
+                result++;
+            }
+            value >>>= 1;
+        }
+        return result;
     }
 }
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index f1f9436..b39d16d 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 import android.security.keymaster.KeyCharacteristics;
@@ -7,6 +23,7 @@
 import java.security.InvalidAlgorithmParameterException;
 import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
 
 import javax.crypto.KeyGeneratorSpi;
 import javax.crypto.SecretKey;
@@ -24,18 +41,47 @@
         }
     }
 
-    public static class HmacSHA256 extends KeyStoreKeyGeneratorSpi {
-        public HmacSHA256() {
+    protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi {
+        protected HmacBase(@KeyStoreKeyConstraints.DigestEnum int digest) {
             super(KeyStoreKeyConstraints.Algorithm.HMAC,
-                    KeyStoreKeyConstraints.Digest.SHA256,
-                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(
-                            KeyStoreKeyConstraints.Digest.SHA256) * 8);
+                    digest,
+                    KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest) * 8);
+        }
+    }
+
+    public static class HmacSHA1 extends HmacBase {
+        public HmacSHA1() {
+            super(KeyStoreKeyConstraints.Digest.SHA1);
+        }
+    }
+
+    public static class HmacSHA224 extends HmacBase {
+        public HmacSHA224() {
+            super(KeyStoreKeyConstraints.Digest.SHA224);
+        }
+    }
+
+    public static class HmacSHA256 extends HmacBase {
+        public HmacSHA256() {
+            super(KeyStoreKeyConstraints.Digest.SHA256);
+        }
+    }
+
+    public static class HmacSHA384 extends HmacBase {
+        public HmacSHA384() {
+            super(KeyStoreKeyConstraints.Digest.SHA384);
+        }
+    }
+
+    public static class HmacSHA512 extends HmacBase {
+        public HmacSHA512() {
+            super(KeyStoreKeyConstraints.Digest.SHA512);
         }
     }
 
     private final KeyStore mKeyStore = KeyStore.getInstance();
     private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
-    private final @KeyStoreKeyConstraints.AlgorithmEnum Integer mDigest;
+    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
     private final int mDefaultKeySizeBits;
 
     private KeyGeneratorSpec mSpec;
@@ -76,12 +122,6 @@
         if (mDigest != null) {
             args.addInt(KeymasterDefs.KM_TAG_DIGEST,
                     KeyStoreKeyConstraints.Digest.toKeymaster(mDigest));
-        }
-        if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
-            if (mDigest == null) {
-                throw new IllegalStateException("Digest algorithm must be specified for key"
-                        + " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
-            }
             Integer digestOutputSizeBytes =
                     KeyStoreKeyConstraints.Digest.getOutputSizeBytes(mDigest);
             if (digestOutputSizeBytes != null) {
@@ -90,60 +130,68 @@
                 args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
             }
         }
+        if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
+            if (mDigest == null) {
+                throw new IllegalStateException("Digest algorithm must be specified for key"
+                        + " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
+            }
+        }
         int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
-        @KeyStoreKeyConstraints.PurposeEnum int purposes = (spec.getPurposes() != null)
-                ? spec.getPurposes()
-                : (KeyStoreKeyConstraints.Purpose.ENCRYPT
-                        | KeyStoreKeyConstraints.Purpose.DECRYPT
-                        | KeyStoreKeyConstraints.Purpose.SIGN
-                        | KeyStoreKeyConstraints.Purpose.VERIFY);
+        @KeyStoreKeyConstraints.PurposeEnum int purposes = spec.getPurposes();
+        @KeyStoreKeyConstraints.BlockModeEnum int blockModes = spec.getBlockModes();
+        if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
+                && (spec.isRandomizedEncryptionRequired())) {
+            @KeyStoreKeyConstraints.BlockModeEnum int incompatibleBlockModes =
+                    blockModes & ~KeyStoreKeyConstraints.BlockMode.IND_CPA_COMPATIBLE_MODES;
+            if (incompatibleBlockModes != 0) {
+                throw new IllegalStateException(
+                        "Randomized encryption (IND-CPA) required but may be violated by block"
+                        + " mode(s): "
+                        + KeyStoreKeyConstraints.BlockMode.allToString(incompatibleBlockModes)
+                        + ". See KeyGeneratorSpec documentation.");
+            }
+        }
+
         for (int keymasterPurpose :
             KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
             args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
         }
-        if (spec.getBlockMode() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE,
-                    KeyStoreKeyConstraints.BlockMode.toKeymaster(spec.getBlockMode()));
+        for (int keymasterBlockMode : KeyStoreKeyConstraints.BlockMode.allToKeymaster(blockModes)) {
+            args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockMode);
         }
-        if (spec.getPadding() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_PADDING,
-                    KeyStoreKeyConstraints.Padding.toKeymaster(spec.getPadding()));
+        for (int keymasterPadding :
+            KeyStoreKeyConstraints.Padding.allToKeymaster(spec.getPaddings())) {
+            args.addInt(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
         }
-        if (spec.getMaxUsesPerBoot() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT, spec.getMaxUsesPerBoot());
-        }
-        if (spec.getMinSecondsBetweenOperations() != null) {
-            args.addInt(KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS,
-                    spec.getMinSecondsBetweenOperations());
-        }
-        if (spec.getUserAuthenticators().isEmpty()) {
+        if (spec.getUserAuthenticators() == 0) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         } else {
-        // TODO: Pass-in user authenticator IDs once the Keymaster API has stabilized
-//            for (int userAuthenticatorId : spec.getUserAuthenticators()) {
-//                args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_ID, userAuthenticatorId);
-//            }
+            args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
+                    KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+                            spec.getUserAuthenticators()));
         }
-        if (spec.getUserAuthenticationValidityDurationSeconds() != null) {
+        if (spec.isInvalidatedOnNewFingerprintEnrolled()) {
+            // TODO: Add the invalidate on fingerprint enrolled constraint once Keymaster supports
+            // that.
+        }
+        if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
             args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
                     spec.getUserAuthenticationValidityDurationSeconds());
         }
-        if (spec.getKeyValidityStart() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
-        }
-        if (spec.getKeyValidityForOriginationEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
-                    spec.getKeyValidityForOriginationEnd());
-        }
-        if (spec.getKeyValidityForConsumptionEnd() != null) {
-            args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
-                    spec.getKeyValidityForConsumptionEnd());
-        }
+        args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
+                (spec.getKeyValidityStart() != null)
+                ? spec.getKeyValidityStart() : new Date(0));
+        args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
+                (spec.getKeyValidityForOriginationEnd() != null)
+                ? spec.getKeyValidityForOriginationEnd() : new Date(Long.MAX_VALUE));
+        args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
+                (spec.getKeyValidityForConsumptionEnd() != null)
+                ? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
 
         if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
-            || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) {
-            // Permit caller-specified IV. This is needed due to the Cipher abstraction.
+                && (!spec.isRandomizedEncryptionRequired())) {
+            // Permit caller-provided IV when encrypting with this key
             args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
         }
 
@@ -159,8 +207,7 @@
         int errorCode = mKeyStore.generateKey(
                 keyAliasInKeystore, args, additionalEntropy, flags, new KeyCharacteristics());
         if (errorCode != KeyStore.NO_ERROR) {
-            throw new CryptoOperationException("Failed to generate key",
-                    KeymasterUtils.getExceptionForKeymasterError(errorCode));
+            throw KeyStore.getCryptoOperationException(errorCode);
         }
         String keyAlgorithmJCA =
                 KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
new file mode 100644
index 0000000..65bb236
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import java.security.spec.KeySpec;
+import java.util.Date;
+
+/**
+ * Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
+ * KeyStore</a>.
+ *
+ * @hide
+ */
+public class KeyStoreKeySpec implements KeySpec {
+    private final String mKeystoreAlias;
+    private final int mKeySize;
+    private final boolean mTeeBacked;
+    private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
+    private final Date mKeyValidityStart;
+    private final Date mKeyValidityForOriginationEnd;
+    private final Date mKeyValidityForConsumptionEnd;
+    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+    private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
+    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+    private final @KeyStoreKeyConstraints.DigestEnum int mDigests;
+    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
+    private final int mUserAuthenticationValidityDurationSeconds;
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
+
+    /**
+     * @hide
+     */
+    KeyStoreKeySpec(String keystoreKeyAlias,
+            boolean teeBacked,
+            @KeyStoreKeyCharacteristics.OriginEnum int origin,
+            int keySize,
+            Date keyValidityStart,
+            Date keyValidityForOriginationEnd,
+            Date keyValidityForConsumptionEnd,
+            @KeyStoreKeyConstraints.PurposeEnum int purposes,
+            @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+            @KeyStoreKeyConstraints.PaddingEnum int paddings,
+            @KeyStoreKeyConstraints.DigestEnum int digests,
+            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
+            int userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
+        mKeystoreAlias = keystoreKeyAlias;
+        mTeeBacked = teeBacked;
+        mOrigin = origin;
+        mKeySize = keySize;
+        mKeyValidityStart = keyValidityStart;
+        mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
+        mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
+        mPurposes = purposes;
+        mAlgorithm = algorithm;
+        mPaddings = paddings;
+        mDigests = digests;
+        mBlockModes = blockModes;
+        mUserAuthenticators = userAuthenticators;
+        mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
+        mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
+     * Gets the entry alias under which the key is stored in the {@code AndroidKeyStore}.
+     */
+    public String getKeystoreAlias() {
+        return mKeystoreAlias;
+    }
+
+    /**
+     * Returns {@code true} if the key is TEE-backed. Key material of TEE-backed keys is available
+     * in plaintext only inside the TEE.
+     */
+    public boolean isTeeBacked() {
+        return mTeeBacked;
+    }
+
+    /**
+     * Gets the origin of the key.
+     */
+    public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
+        return mOrigin;
+    }
+
+    /**
+     * Gets the size of the key in bits.
+     */
+    public int getKeySize() {
+        return mKeySize;
+    }
+
+    /**
+     * Gets the time instant before which the key is not yet valid.
+     *
+     * @return instant or {@code null} if not restricted.
+     */
+    public Date getKeyValidityStart() {
+        return mKeyValidityStart;
+    }
+
+    /**
+     * Gets the time instant after which the key is no long valid for decryption and verification.
+     *
+     * @return instant or {@code null} if not restricted.
+     */
+    public Date getKeyValidityForConsumptionEnd() {
+        return mKeyValidityForConsumptionEnd;
+    }
+
+    /**
+     * Gets the time instant after which the key is no long valid for encryption and signing.
+     *
+     * @return instant or {@code null} if not restricted.
+     */
+    public Date getKeyValidityForOriginationEnd() {
+        return mKeyValidityForOriginationEnd;
+    }
+
+    /**
+     * Gets the set of purposes for which the key can be used.
+     */
+    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+        return mPurposes;
+    }
+
+    /**
+     * Gets the algorithm of the key.
+     */
+    public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
+        return mAlgorithm;
+    }
+
+    /**
+     * Gets the set of block modes with which the key can be used.
+     */
+    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
+        return mBlockModes;
+    }
+
+    /**
+     * Gets the set of padding modes with which the key can be used.
+     */
+    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
+        return mPaddings;
+    }
+
+    /**
+     * Gets the set of digest algorithms with which the key can be used.
+     */
+    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
+        return mDigests;
+    }
+
+    /**
+     * Gets the set of user authenticators which protect access to the key. The key can only be used
+     * iff the user has authenticated to at least one of these user authenticators.
+     *
+     * @return user authenticators or {@code 0} if the key can be used without user authentication.
+     */
+    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+        return mUserAuthenticators;
+    }
+
+    /**
+     * Gets the set of user authenticators for which the TEE enforces access restrictions for this
+     * key. This is a subset of the user authentications returned by
+     * {@link #getUserAuthenticators()}.
+     */
+    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
+        return mTeeEnforcedUserAuthenticators;
+    }
+
+    /**
+     * Gets the duration of time (seconds) for which the key can be used after the user
+     * successfully authenticates to one of the associated user authenticators.
+     *
+     * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
+     *         is required for every use of the key.
+     */
+    public int getUserAuthenticationValidityDurationSeconds() {
+        return mUserAuthenticationValidityDurationSeconds;
+    }
+
+    /**
+     * Returns {@code true} if this key will be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
+     */
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
+    }
+}
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 2428c2a..751eef5 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -18,16 +18,15 @@
 
 import android.content.Context;
 
-import java.security.KeyPairGenerator;
+import java.security.Key;
 import java.security.KeyStore.ProtectionParameter;
-import java.util.Collections;
 import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+
+import javax.crypto.Cipher;
 
 /**
- * This provides the optional parameters that can be specified for
- * {@code KeyStore} entries that work with
+ * Parameters specifying how to secure and restrict the use of a key being
+ * imported into the
  * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
  * facility</a>. The Android KeyStore facility is accessed through a
  * {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
@@ -38,41 +37,35 @@
  * there is only one logical instance of the {@code KeyStore} per application
  * UID so apps using the {@code sharedUid} facility will also share a
  * {@code KeyStore}.
- * <p>
- * Keys may be generated using the {@link KeyPairGenerator} facility with a
- * {@link KeyPairGeneratorSpec} to specify the entry's {@code alias}. A
- * self-signed X.509 certificate will be attached to generated entries, but that
- * may be replaced at a later time by a certificate signed by a real Certificate
- * Authority.
  */
 public final class KeyStoreParameter implements ProtectionParameter {
     private int mFlags;
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
-    private final @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
-    private final @KeyStoreKeyConstraints.AlgorithmEnum Integer mAlgorithm;
-    private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
-    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
-    private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
-    private final Integer mMinSecondsBetweenOperations;
-    private final Integer mMaxUsesPerBoot;
-    private final Set<Integer> mUserAuthenticators;
-    private final Integer mUserAuthenticationValidityDurationSeconds;
+    private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+    private final @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+    private final @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
+    private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+    private final boolean mRandomizedEncryptionRequired;
+    private final @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+    private final int mUserAuthenticationValidityDurationSeconds;
+    private final boolean mInvalidatedOnNewFingerprintEnrolled;
 
-    private KeyStoreParameter(int flags, Date keyValidityStart,
-            Date keyValidityForOriginationEnd, Date keyValidityForConsumptionEnd,
-            @KeyStoreKeyConstraints.PurposeEnum Integer purposes,
-            @KeyStoreKeyConstraints.AlgorithmEnum Integer algorithm,
-            @KeyStoreKeyConstraints.PaddingEnum Integer padding,
-            @KeyStoreKeyConstraints.DigestEnum Integer digest,
-            @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
-            Integer minSecondsBetweenOperations,
-            Integer maxUsesPerBoot,
-            Set<Integer> userAuthenticators,
-            Integer userAuthenticationValidityDurationSeconds) {
-        if ((userAuthenticationValidityDurationSeconds != null)
-                && (userAuthenticationValidityDurationSeconds < 0)) {
+    private KeyStoreParameter(int flags,
+            Date keyValidityStart,
+            Date keyValidityForOriginationEnd,
+            Date keyValidityForConsumptionEnd,
+            @KeyStoreKeyConstraints.PurposeEnum int purposes,
+            @KeyStoreKeyConstraints.PaddingEnum int paddings,
+            @KeyStoreKeyConstraints.DigestEnum Integer digests,
+            @KeyStoreKeyConstraints.BlockModeEnum int blockModes,
+            boolean randomizedEncryptionRequired,
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators,
+            int userAuthenticationValidityDurationSeconds,
+            boolean invalidatedOnNewFingerprintEnrolled) {
+        if ((userAuthenticationValidityDurationSeconds < 0)
+                && (userAuthenticationValidityDurationSeconds != -1)) {
             throw new IllegalArgumentException(
                     "userAuthenticationValidityDurationSeconds must not be negative");
         }
@@ -82,16 +75,13 @@
         mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
         mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
         mPurposes = purposes;
-        mAlgorithm = algorithm;
-        mPadding = padding;
-        mDigest = digest;
-        mBlockMode = blockMode;
-        mMinSecondsBetweenOperations = minSecondsBetweenOperations;
-        mMaxUsesPerBoot = maxUsesPerBoot;
-        mUserAuthenticators = (userAuthenticators != null)
-                ? new HashSet<Integer>(userAuthenticators)
-                : Collections.<Integer>emptySet();
+        mPaddings = paddings;
+        mDigests = digests;
+        mBlockModes = blockModes;
+        mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+        mUserAuthenticators = userAuthenticators;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mInvalidatedOnNewFingerprintEnrolled = invalidatedOnNewFingerprintEnrolled;
     }
 
     /**
@@ -142,109 +132,113 @@
     }
 
     /**
-     * Gets the set of purposes for which the key can be used to the provided set of purposes.
-     *
-     * @return set of purposes or {@code null} if the key can be used for any purpose.
+     * Gets the set of purposes for which the key can be used.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.PurposeEnum Integer getPurposes() {
+    public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
         return mPurposes;
     }
 
     /**
-     * Gets the algorithm to which the key is restricted.
+     * Gets the set of padding schemes to which the key is restricted.
      *
-     * @return algorithm or {@code null} if it's not restricted.
      * @hide
      */
-    public @KeyStoreKeyConstraints.AlgorithmEnum Integer getAlgorithm() {
-        return mAlgorithm;
+    public @KeyStoreKeyConstraints.PaddingEnum int getPaddings() {
+        return mPaddings;
     }
 
     /**
-     * Gets the padding scheme to which the key is restricted.
+     * Gets the set of digests to which the key is restricted.
      *
-     * @return padding scheme or {@code null} if the padding scheme is not restricted.
+     * @throws IllegalStateException if this restriction has not been specified.
+     *
+     * @see #isDigestsSpecified()
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
-        return mPadding;
+    public @KeyStoreKeyConstraints.DigestEnum int getDigests() {
+        if (mDigests == null) {
+            throw new IllegalStateException("Digests not specified");
+        }
+        return mDigests;
     }
 
     /**
-     * Gets the digest to which the key is restricted when generating Message Authentication Codes
-     * (MACs).
+     * Returns {@code true} if digest restrictions have been specified.
      *
-     * @return digest or {@code null} if the digest is not restricted.
+     * @see #getDigests()
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.DigestEnum Integer getDigest() {
-        return mDigest;
+    public boolean isDigestsSpecified() {
+        return mDigests != null;
     }
 
     /**
-     * Gets the block mode to which the key is restricted when used for encryption or decryption.
-     *
-     * @return block more or {@code null} if block mode is not restricted.
+     * Gets the set of block modes to which the key is restricted.
      *
      * @hide
      */
-    public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
-        return mBlockMode;
+    public @KeyStoreKeyConstraints.BlockModeEnum int getBlockModes() {
+        return mBlockModes;
     }
 
     /**
-     * Gets the minimum number of seconds that must expire since the most recent use of the key
-     * before it can be used again.
-     *
-     * @return number of seconds or {@code null} if there is no restriction on how frequently a key
-     *         can be used.
+     * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+     * different ciphertexts for the same plaintext every time. The formal cryptographic property
+     * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+     * IND-CPA})</em>. This property is important because it mitigates several classes of
+     * weaknesses due to which ciphertext may leak information about plaintext. For example, if a
+     * given plaintext always produces the same ciphertext, an attacker may see the repeated
+     * ciphertexts and be able to deduce something about the plaintext.
      *
      * @hide
      */
-    public Integer getMinSecondsBetweenOperations() {
-        return mMinSecondsBetweenOperations;
+    public boolean isRandomizedEncryptionRequired() {
+        return mRandomizedEncryptionRequired;
     }
 
     /**
-     * Gets the number of times the key can be used without rebooting the device.
+     * Gets the set of user authenticators which protect access to this key. The key can only be
+     * used iff the user has authenticated to at least one of these user authenticators.
      *
-     * @return maximum number of times or {@code null} if there is no restriction.
-     * @hide
-     */
-    public Integer getMaxUsesPerBoot() {
-        return mMaxUsesPerBoot;
-    }
-
-    /**
-     * Gets the user authenticators which protect access to this key. The key can only be used iff
-     * the user has authenticated to at least one of these user authenticators.
-     *
-     * @return user authenticators or empty set if the key can be used without user authentication.
+     * @return user authenticators or {@code 0} if the key can be used without user authentication.
      *
      * @hide
      */
-    public Set<Integer> getUserAuthenticators() {
-        return new HashSet<Integer>(mUserAuthenticators);
+    public @KeyStoreKeyConstraints.UserAuthenticatorEnum int getUserAuthenticators() {
+        return mUserAuthenticators;
     }
 
     /**
      * Gets the duration of time (seconds) for which this key can be used after the user
      * successfully authenticates to one of the associated user authenticators.
      *
-     * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+     * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
      *         is required for every use of the key.
      *
      * @hide
      */
-    public Integer getUserAuthenticationValidityDurationSeconds() {
+    public int getUserAuthenticationValidityDurationSeconds() {
         return mUserAuthenticationValidityDurationSeconds;
     }
 
     /**
+     * Returns {@code true} if this key must be permanently invalidated once a new fingerprint is
+     * enrolled. This constraint only has effect if fingerprint reader is one of the user
+     * authenticators protecting access to this key.
+     *
+     * @see #getUserAuthenticators()
+     *
+     * @hide
+     */
+    public boolean isInvalidatedOnNewFingerprintEnrolled() {
+        return mInvalidatedOnNewFingerprintEnrolled;
+    }
+
+    /**
      * Builder class for {@link KeyStoreParameter} objects.
      * <p>
      * This will build protection parameters for use with the
@@ -266,15 +260,14 @@
         private Date mKeyValidityStart;
         private Date mKeyValidityForOriginationEnd;
         private Date mKeyValidityForConsumptionEnd;
-        private @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
-        private @KeyStoreKeyConstraints.AlgorithmEnum Integer mAlgorithm;
-        private @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
-        private @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
-        private @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
-        private Integer mMinSecondsBetweenOperations;
-        private Integer mMaxUsesPerBoot;
-        private Set<Integer> mUserAuthenticators;
-        private Integer mUserAuthenticationValidityDurationSeconds;
+        private @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
+        private @KeyStoreKeyConstraints.PaddingEnum int mPaddings;
+        private @KeyStoreKeyConstraints.DigestEnum Integer mDigests;
+        private @KeyStoreKeyConstraints.BlockModeEnum int mBlockModes;
+        private boolean mRandomizedEncryptionRequired = true;
+        private @KeyStoreKeyConstraints.UserAuthenticatorEnum int mUserAuthenticators;
+        private int mUserAuthenticationValidityDurationSeconds = -1;
+        private boolean mInvalidatedOnNewFingerprintEnrolled;
 
         /**
          * Creates a new instance of the {@code Builder} with the given
@@ -308,7 +301,7 @@
         /**
          * Sets the time instant before which the key is not yet valid.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityEnd(Date)
          *
@@ -322,7 +315,7 @@
         /**
          * Sets the time instant after which the key is no longer valid.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityStart(Date)
          * @see #setKeyValidityForConsumptionEnd(Date)
@@ -339,7 +332,7 @@
         /**
          * Sets the time instant after which the key is no longer valid for encryption and signing.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForConsumptionEnd(Date)
          *
@@ -354,7 +347,7 @@
          * Sets the time instant after which the key is no longer valid for decryption and
          * verification.
          *
-         * <b>By default, the key is valid at any instant.
+         * <p>By default, the key is valid at any instant.
          *
          * @see #setKeyValidityForOriginationEnd(Date)
          *
@@ -366,9 +359,9 @@
         }
 
         /**
-         * Restricts the purposes for which the key can be used to the provided set of purposes.
+         * Restricts the key to being used only for the provided set of purposes.
          *
-         * <p>By default, the key can be used for encryption, decryption, signing, and verification.
+         * <p>This restriction must be specified. There is no default.
          *
          * @hide
          */
@@ -378,83 +371,84 @@
         }
 
         /**
-         * Sets the algorithm of the key.
-         *
-         * <p>The algorithm of symmetric keys can be deduced from the key itself. Thus, explicitly
-         * specifying the algorithm of symmetric keys using this method is not necessary.
-         *
-         * @hide
-         */
-        public Builder setAlgorithm(@KeyStoreKeyConstraints.AlgorithmEnum int algorithm) {
-            mAlgorithm = algorithm;
-            return this;
-        }
-
-        /**
-         * Restricts the key to being used only with the provided padding scheme. Attempts to use
+         * Restricts the key to being used only with the provided padding schemes. Attempts to use
          * the key with any other padding will be rejected.
          *
          * <p>This restriction must be specified for keys which are used for encryption/decryption.
          *
          * @hide
          */
-        public Builder setPadding(@KeyStoreKeyConstraints.PaddingEnum int padding) {
-            mPadding = padding;
+        public Builder setPaddings(@KeyStoreKeyConstraints.PaddingEnum int paddings) {
+            mPaddings = paddings;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided digest when generating Message
-         * Authentication Codes (MACs). Attempts to use the key with any other digest will be
-         * rejected.
+         * Restricts the key to being used only with the provided digests when generating signatures
+         * or HMACs. Attempts to use the key with any other digest will be rejected.
          *
-         * <p>For MAC keys, the default is to restrict to the digest specified in the key algorithm
-         * name.
-         *
-         * @see java.security.Key#getAlgorithm()
+         * <p>For HMAC keys, the default is to restrict to the digest specified in
+         * {@link Key#getAlgorithm()}. For asymmetric signing keys this constraint must be specified
+         * because there is no default.
          *
          * @hide
          */
-        public Builder setDigest(@KeyStoreKeyConstraints.DigestEnum int digest) {
-            mDigest = digest;
+        public Builder setDigests(@KeyStoreKeyConstraints.DigestEnum int digests) {
+            mDigests = digests;
             return this;
         }
 
         /**
-         * Restricts the key to being used only with the provided block mode when encrypting or
-         * decrypting. Attempts to use the key with any other block modes will be rejected.
+         * Restricts the key to being used only with the provided block modes. Attempts to use the
+         * key with any other block modes will be rejected.
          *
-         * <p>This restriction must be specified for keys which are used for encryption/decryption.
+         * <p>This restriction must be specified for symmetric encryption/decryption keys.
          *
          * @hide
          */
-        public Builder setBlockMode(@KeyStoreKeyConstraints.BlockModeEnum int blockMode) {
-            mBlockMode = blockMode;
+        public Builder setBlockModes(@KeyStoreKeyConstraints.BlockModeEnum int blockModes) {
+            mBlockModes = blockModes;
             return this;
         }
 
         /**
-         * Sets the minimum number of seconds that must expire since the most recent use of the key
-         * before it can be used again.
+         * Sets whether encryption using this key must be sufficiently randomized to produce
+         * different ciphertexts for the same plaintext every time. The formal cryptographic
+         * property being required is <em>indistinguishability under chosen-plaintext attack
+         * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+         * of weaknesses due to which ciphertext may leak information about plaintext. For example,
+         * if a given plaintext always produces the same ciphertext, an attacker may see the
+         * repeated ciphertexts and be able to deduce something about the plaintext.
          *
-         * <p>By default, there is no restriction on how frequently a key can be used.
+         * <p>By default, {@code IND-CPA} is required.
+         *
+         * <p>When {@code IND-CPA} is required:
+         * <ul>
+         * <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using
+         * {@code ECB} mode or RSA encryption without padding, are prohibited;</li>
+         * <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC},
+         * {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when
+         * encrypting, to ensure that only random IVs are used.</li>
+         *
+         * <p>Before disabling this requirement, consider the following approaches instead:
+         * <ul>
+         * <li>If you are generating a random IV for encryption and then initializing a {@code}
+         * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
+         * instead. This will occur if the {@code Cipher} is initialized for encryption without an
+         * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
+         * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
+         * random, such as the name of the file being encrypted, or transaction ID, or password,
+         * or a device identifier), consider changing your design to use a random IV which will then
+         * be provided in addition to the ciphertext to the entities which need to decrypt the
+         * ciphertext.</li>
+         * <li>If you are using RSA encryption without padding, consider switching to padding
+         * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
+         * </ul>
          *
          * @hide
          */
-        public Builder setMinSecondsBetweenOperations(int seconds) {
-            mMinSecondsBetweenOperations = seconds;
-            return this;
-        }
-
-        /**
-         * Sets the maximum number of times a key can be used without rebooting the device.
-         *
-         * <p>By default, the key can be used for an unlimited number of times.
-         *
-         * @hide
-         */
-        public Builder setMaxUsesPerBoot(int count) {
-            mMaxUsesPerBoot = count;
+        public Builder setRandomizedEncryptionRequired(boolean required) {
+            mRandomizedEncryptionRequired = required;
             return this;
         }
 
@@ -464,16 +458,16 @@
          *
          * <p>By default, the key can be used without user authentication.
          *
-         * @param userAuthenticators user authenticators or empty list if this key can be accessed
+         * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed
          *        without user authentication.
          *
          * @see #setUserAuthenticationValidityDurationSeconds(int)
          *
          * @hide
          */
-        public Builder setUserAuthenticators(Set<Integer> userAuthenticators) {
-            mUserAuthenticators =
-                    (userAuthenticators != null) ? new HashSet<Integer>(userAuthenticators) : null;
+        public Builder setUserAuthenticators(
+                @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators) {
+            mUserAuthenticators = userAuthenticators;
             return this;
         }
 
@@ -486,7 +480,7 @@
          * @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
          *        every use of the key.
          *
-         * @see #setUserAuthenticators(Set)
+         * @see #setUserAuthenticators(int)
          *
          * @hide
          */
@@ -496,17 +490,40 @@
         }
 
         /**
+         * Sets whether this key must be invalidated (permanently) whenever a new fingerprint is
+         * enrolled. This only has effect if fingerprint reader is one of the user authenticators
+         * protecting access to the key.
+         *
+         * <p>By default, enrolling a new fingerprint does not invalidate the key.
+         *
+         * @see #setUserAuthenticators(Set)
+         *
+         * @hide
+         */
+        public Builder setInvalidatedOnNewFingerprintEnrolled(boolean invalidated) {
+            mInvalidatedOnNewFingerprintEnrolled = invalidated;
+            return this;
+        }
+
+        /**
          * Builds the instance of the {@code KeyStoreParameter}.
          *
          * @throws IllegalArgumentException if a required field is missing
          * @return built instance of {@code KeyStoreParameter}
          */
         public KeyStoreParameter build() {
-            return new KeyStoreParameter(mFlags, mKeyValidityStart,
-                    mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd, mPurposes,
-                    mAlgorithm, mPadding, mDigest, mBlockMode, mMinSecondsBetweenOperations,
-                    mMaxUsesPerBoot, mUserAuthenticators,
-                    mUserAuthenticationValidityDurationSeconds);
+            return new KeyStoreParameter(mFlags,
+                    mKeyValidityStart,
+                    mKeyValidityForOriginationEnd,
+                    mKeyValidityForConsumptionEnd,
+                    mPurposes,
+                    mPaddings,
+                    mDigests,
+                    mBlockModes,
+                    mRandomizedEncryptionRequired,
+                    mUserAuthenticators,
+                    mUserAuthenticationValidityDurationSeconds,
+                    mInvalidatedOnNewFingerprintEnrolled);
         }
     }
 }
diff --git a/keystore/java/android/security/KeyStoreSecretKey.java b/keystore/java/android/security/KeyStoreSecretKey.java
index 9410127..7f0e3d3 100644
--- a/keystore/java/android/security/KeyStoreSecretKey.java
+++ b/keystore/java/android/security/KeyStoreSecretKey.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
 import javax.crypto.SecretKey;
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
new file mode 100644
index 0000000..a5e87d1
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
+
+import java.security.InvalidKeyException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Date;
+
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactorySpi;
+import javax.crypto.spec.SecretKeySpec;
+
+/**
+ * {@link SecretKeyFactorySpi} backed by Android KeyStore.
+ *
+ * @hide
+ */
+public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
+
+    private final KeyStore mKeyStore = KeyStore.getInstance();
+
+    @Override
+    protected KeySpec engineGetKeySpec(SecretKey key,
+            @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
+        if (keySpecClass == null) {
+            throw new InvalidKeySpecException("keySpecClass == null");
+        }
+        if (!(key instanceof KeyStoreSecretKey)) {
+            throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
+                    ((key != null) ? key.getClass().getName() : "null"));
+        }
+        if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
+            throw new InvalidKeySpecException(
+                    "Key material export of Android KeyStore keys is not supported");
+        }
+        if (!KeyStoreKeySpec.class.equals(keySpecClass)) {
+            throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
+        }
+        String keyAliasInKeystore = ((KeyStoreSecretKey) key).getAlias();
+        String entryAlias;
+        if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)) {
+            entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
+        } else {
+            throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
+        }
+
+        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+        int errorCode =
+                mKeyStore.getKeyCharacteristics(keyAliasInKeystore, null, null, keyCharacteristics);
+        if (errorCode != KeyStore.NO_ERROR) {
+            throw new InvalidKeySpecException("Failed to obtain information about key."
+                    + " Keystore error: " + errorCode);
+        }
+
+        boolean teeBacked;
+        @KeyStoreKeyCharacteristics.OriginEnum int origin;
+        int keySize;
+        @KeyStoreKeyConstraints.PurposeEnum int purposes;
+        @KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
+        @KeyStoreKeyConstraints.PaddingEnum int paddings;
+        @KeyStoreKeyConstraints.DigestEnum int digests;
+        @KeyStoreKeyConstraints.BlockModeEnum int blockModes;
+        @KeyStoreKeyConstraints.UserAuthenticatorEnum int userAuthenticators;
+        @KeyStoreKeyConstraints.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
+        try {
+            if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
+                teeBacked = true;
+                origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
+                        keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
+            } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
+                teeBacked = false;
+                origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(
+                        keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
+            } else {
+                throw new InvalidKeySpecException("Key origin not available");
+            }
+            Integer keySizeInteger =
+                    KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
+            if (keySizeInteger == null) {
+                throw new InvalidKeySpecException("Key size not available");
+            }
+            keySize = keySizeInteger;
+            purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
+                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
+            Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
+            if (alg == null) {
+                throw new InvalidKeySpecException("Key algorithm not available");
+            }
+            algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
+            paddings = KeyStoreKeyConstraints.Padding.allFromKeymaster(
+                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING));
+            digests = KeyStoreKeyConstraints.Digest.allFromKeymaster(
+                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST));
+            blockModes = KeyStoreKeyConstraints.BlockMode.allFromKeymaster(
+                    KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE));
+
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            int swEnforcedKeymasterUserAuthenticators =
+                    keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            int hwEnforcedKeymasterUserAuthenticators =
+                    keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+            @KeyStoreKeyConstraints.UserAuthenticatorEnum
+            int keymasterUserAuthenticators =
+                    swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators;
+            userAuthenticators = KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+                    keymasterUserAuthenticators);
+            teeEnforcedUserAuthenticators =
+                    KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
+                            hwEnforcedKeymasterUserAuthenticators);
+        } catch (IllegalArgumentException e) {
+            throw new InvalidKeySpecException("Unsupported key characteristic", e);
+        }
+
+        Date keyValidityStart =
+                KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+        if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
+            keyValidityStart = null;
+        }
+        Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
+                KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+        if ((keyValidityForOriginationEnd != null)
+                && (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
+            keyValidityForOriginationEnd = null;
+        }
+        Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
+                KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+        if ((keyValidityForConsumptionEnd != null)
+                && (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
+            keyValidityForConsumptionEnd = null;
+        }
+        Integer userAuthenticationValidityDurationSeconds =
+                KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT);
+
+        // TODO: Populate the value below from key characteristics once Keymaster is ready.
+        boolean invalidatedOnNewFingerprintEnrolled = false;
+
+        return new KeyStoreKeySpec(entryAlias,
+                teeBacked,
+                origin,
+                keySize,
+                keyValidityStart,
+                keyValidityForOriginationEnd,
+                keyValidityForConsumptionEnd,
+                purposes,
+                algorithm,
+                paddings,
+                digests,
+                blockModes,
+                userAuthenticators,
+                teeEnforcedUserAuthenticators,
+                ((userAuthenticationValidityDurationSeconds != null)
+                        ? userAuthenticationValidityDurationSeconds : -1),
+                invalidatedOnNewFingerprintEnrolled);
+    }
+
+    @Override
+    protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
+        throw new UnsupportedOperationException(
+                "Key import into Android KeyStore is not supported");
+    }
+
+    @Override
+    protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
+        throw new UnsupportedOperationException(
+                "Key import into Android KeyStore is not supported");
+    }
+}
diff --git a/keystore/java/android/security/KeymasterException.java b/keystore/java/android/security/KeymasterException.java
deleted file mode 100644
index bc8198f..0000000
--- a/keystore/java/android/security/KeymasterException.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package android.security;
-
-/**
- * Keymaster exception.
- *
- * @hide
- */
-public class KeymasterException extends Exception {
-
-    private final int mErrorCode;
-
-    public KeymasterException(int errorCode, String message) {
-        super(message);
-        mErrorCode = errorCode;
-    }
-
-    public int getErrorCode() {
-        return mErrorCode;
-    }
-}
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 4f17586..3143d4d 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -1,6 +1,26 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package android.security;
 
-import android.security.keymaster.KeymasterDefs;
+import android.security.keymaster.KeyCharacteristics;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
 
 /**
  * @hide
@@ -8,16 +28,36 @@
 public abstract class KeymasterUtils {
     private KeymasterUtils() {}
 
-    public static KeymasterException getExceptionForKeymasterError(int keymasterErrorCode) {
-        switch (keymasterErrorCode) {
-            case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
-                // The name of this parameter significantly differs between Keymaster and framework
-                // APIs. Use the framework wording to make life easier for developers.
-                return new KeymasterException(keymasterErrorCode,
-                        "Invalid user authentication validity duration");
-            default:
-                return new KeymasterException(keymasterErrorCode,
-                        KeymasterDefs.getErrorMessage(keymasterErrorCode));
+    public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
+        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+            return keyCharacteristics.hwEnforced.getInt(tag, -1);
+        } else if (keyCharacteristics.swEnforced.containsTag(tag)) {
+            return keyCharacteristics.swEnforced.getInt(tag, -1);
+        } else {
+            return null;
+        }
+    }
+
+    public static List<Integer> getInts(KeyCharacteristics keyCharacteristics, int tag) {
+        List<Integer> result = new ArrayList<Integer>();
+        result.addAll(keyCharacteristics.hwEnforced.getInts(tag));
+        result.addAll(keyCharacteristics.swEnforced.getInts(tag));
+        return result;
+    }
+
+    public static Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
+        Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
+        if (result == null) {
+            result = keyCharacteristics.swEnforced.getDate(tag, null);
+        }
+        return result;
+    }
+
+    public static boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
+        if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+            return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+        } else {
+            return keyCharacteristics.swEnforced.getBoolean(tag, false);
         }
     }
 }
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
new file mode 100644
index 0000000..6da4a2a
--- /dev/null
+++ b/keystore/java/android/security/NewFingerprintEnrolledException.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the key used by the
+ * operation is permanently invalid because a new fingerprint was enrolled.
+ *
+ * @hide
+ */
+public class NewFingerprintEnrolledException extends CryptoOperationException {
+
+    /**
+     * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
+     */
+    public NewFingerprintEnrolledException() {
+        super("Invalid key: new fingerprint enrolled");
+    }
+
+    /**
+     * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
+     * no cause.
+     */
+    public NewFingerprintEnrolledException(String message) {
+        super(message);
+    }
+}
diff --git a/keystore/java/android/security/UserNotAuthenticatedException.java b/keystore/java/android/security/UserNotAuthenticatedException.java
new file mode 100644
index 0000000..e6342ef
--- /dev/null
+++ b/keystore/java/android/security/UserNotAuthenticatedException.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+/**
+ * Indicates that a cryptographic operation could not be performed because the user has not been
+ * authenticated recently enough.
+ *
+ * @hide
+ */
+public class UserNotAuthenticatedException extends CryptoOperationException {
+
+    /**
+     * Constructs a new {@code UserNotAuthenticatedException} without detail message and cause.
+     */
+    public UserNotAuthenticatedException() {
+        super("User not authenticated");
+    }
+
+    /**
+     * Constructs a new {@code UserNotAuthenticatedException} with the provided detail message and
+     * no cause.
+     */
+    public UserNotAuthenticatedException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code UserNotAuthenticatedException} with the provided detail message and
+     * cause.
+     */
+    public UserNotAuthenticatedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 7468fb5..1a5552a 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -294,14 +294,14 @@
 
     public void testSaw_ungrantedUid_Bluetooth() throws Exception {
         String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
-        assertNull(results1);
+        assertEquals(0, results1.length);
 
         mKeyStore.password(TEST_PASSWD);
         mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
         mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
 
         String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
-        assertNull(results2);
+        assertEquals(0, results2.length);
     }
 
     public void testSaw_grantedUid_Wifi() throws Exception {
@@ -712,6 +712,7 @@
         args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
         args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
                 RSAKeyGenParameterSpec.F4.longValue());
@@ -735,6 +736,7 @@
         args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
         args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
                 RSAKeyGenParameterSpec.F4.longValue());
@@ -769,6 +771,7 @@
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
         args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
+        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
         args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
                 RSAKeyGenParameterSpec.F4.longValue());
@@ -795,7 +798,7 @@
         // TODO: Verify we have an RSA public key that's well formed.
     }
 
-    public void testAesOcbEncryptSuccess() throws Exception {
+    public void testAesGcmEncryptSuccess() throws Exception {
         String name = "test";
         KeymasterArguments args = new KeymasterArguments();
         args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
@@ -803,9 +806,10 @@
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
-        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
         args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
         args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
+        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
 
         KeyCharacteristics outCharacteristics = new KeyCharacteristics();
         int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
@@ -838,6 +842,7 @@
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
         args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mode);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, size);
+        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
         return mKeyStore.importKey(name, args, KeymasterDefs.KM_KEY_FORMAT_RAW, key, 0,
                 new KeyCharacteristics());
     }
@@ -898,9 +903,8 @@
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
-        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
-        args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
-        args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
+        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
 
         KeyCharacteristics outCharacteristics = new KeyCharacteristics();
         int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
@@ -922,4 +926,28 @@
         assertEquals("Operation should be pruned", KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE,
                 mKeyStore.update(first, null, new byte[] {0x01}).resultCode);
     }
+
+    public void testAuthNeeded() throws Exception {
+        String name = "test";
+        KeymasterArguments args = new KeymasterArguments();
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
+        args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
+        args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
+        args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
+        args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
+        args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 1);
+
+        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
+        int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
+        KeymasterArguments out = new KeymasterArguments();
+        assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
+        OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
+                true, args, null, out);
+        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
+        IBinder token = result.token;
+        result = mKeyStore.update(token, null, new byte[] {0x01, 0x02, 0x03, 0x04});
+        assertEquals("Update should require authorization",
+                KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED, result.resultCode);
+    }
 }
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 0a210d6..a4100a2 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -45,8 +45,9 @@
 /**
  * Other constants:
  */
-// For the edge of the penumbra, the opacity is 0.
-#define OUTER_OPACITY (0.0f)
+// For the edge of the penumbra, the opacity is 0. After transform (1 - alpha),
+// it is 1.
+#define TRANSFORMED_OUTER_OPACITY (1.0f)
 
 // Once the alpha difference is greater than this threshold, we will allocate extra
 // edge vertices.
@@ -83,11 +84,13 @@
     return 1.0 / (1 + MathUtils::max(factoredZ, 0.0f));
 }
 
+// The shader is using gaussian function e^-(1-x)*(1-x)*4, therefore, we transform
+// the alpha value to (1 - alpha)
 inline float getTransformedAlphaFromAlpha(float alpha) {
-    return acosf(1.0f - 2.0f * alpha);
+    return 1.0f - alpha;
 }
 
-// The output is ranged from 0 to M_PI.
+// The output is ranged from 0 to 1.
 inline float getTransformedAlphaFromFactoredZ(float factoredZ) {
     return getTransformedAlphaFromAlpha(getAlphaFromFactoredZ(factoredZ));
 }
@@ -249,7 +252,7 @@
             indexBuffer[indexBufferIndex++] = vertexBufferIndex;
             indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
             AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x,
-                    outerVertex.y, OUTER_OPACITY);
+                    outerVertex.y, TRANSFORMED_OUTER_OPACITY);
 
             if (j == 0) {
                 outerStart = outerVertex;
@@ -285,7 +288,7 @@
                     (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
                 indexBuffer[indexBufferIndex++] = vertexBufferIndex;
                 AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
-                        currentOuter.y, OUTER_OPACITY);
+                        currentOuter.y, TRANSFORMED_OUTER_OPACITY);
 
                 if (!isCasterOpaque) {
                     umbraVertices[umbraIndex++] = vertexBufferIndex;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 6bef7c7..c79ae77 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -46,51 +46,11 @@
 // blur inputs smaller than this constant will bypass renderscript
 #define RS_MIN_INPUT_CUTOFF 10000
 
-#define USE_GLOPS true
-
 ///////////////////////////////////////////////////////////////////////////////
 // TextSetupFunctor
 ///////////////////////////////////////////////////////////////////////////////
-void TextSetupFunctor::setup(GLenum glyphFormat) {
-    renderer->setupDraw();
-    renderer->setupDrawTextGamma(paint);
-    renderer->setupDrawDirtyRegionsDisabled();
-    renderer->setupDrawWithTexture(glyphFormat == GL_ALPHA);
-    switch (glyphFormat) {
-        case GL_ALPHA: {
-            renderer->setupDrawAlpha8Color(paint->getColor(), alpha);
-            break;
-        }
-        case GL_RGBA: {
-            float floatAlpha = alpha / 255.0f;
-            renderer->setupDrawColor(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
-            break;
-        }
-        default: {
-#if DEBUG_FONT_RENDERER
-            ALOGD("TextSetupFunctor: called with unknown glyph format %x", glyphFormat);
-#endif
-            break;
-        }
-    }
-    renderer->setupDrawColorFilter(paint->getColorFilter());
-    renderer->setupDrawShader(paint->getShader());
-    renderer->setupDrawBlending(paint);
-    renderer->setupDrawProgram();
-    renderer->setupDrawModelView(kModelViewMode_Translate, false,
-            0.0f, 0.0f, 0.0f, 0.0f, pureTranslate);
-    // Calling setupDrawTexture with the name 0 will enable the
-    // uv attributes and increase the texture unit count
-    // texture binding will be performed by the font renderer as
-    // needed
-    renderer->setupDrawTexture(0);
-    renderer->setupDrawPureColorUniforms();
-    renderer->setupDrawColorFilterUniforms(paint->getColorFilter());
-    renderer->setupDrawShaderUniforms(paint->getShader(), pureTranslate);
-    renderer->setupDrawTextGammaUniforms();
-}
 
-void TextSetupFunctor::draw(CacheTexture& texture, bool linearFiltering) {
+void TextDrawFunctor::draw(CacheTexture& texture, bool linearFiltering) {
     int textureFillFlags = static_cast<int>(texture.getFormat() == GL_ALPHA
             ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
     if (linearFiltering) {
@@ -204,6 +164,8 @@
     for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
         mRGBACacheTextures[i]->init();
     }
+
+    mDrawn = false;
 }
 
 void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
@@ -508,11 +470,6 @@
 void FontRenderer::issueDrawCommand(Vector<CacheTexture*>& cacheTextures) {
     if (!mFunctor) return;
 
-#if !USE_GLOPS
-    Caches& caches = mFunctor->renderer->getCaches();
-    RenderState& renderState = mFunctor->renderer->renderState();
-#endif
-
     bool first = true;
     bool forceRebind = false;
     for (uint32_t i = 0; i < cacheTextures.size(); i++) {
@@ -520,37 +477,12 @@
         if (texture->canDraw()) {
             if (first) {
                 checkTextureUpdate();
-#if !USE_GLOPS
-                mFunctor->setup(texture->getFormat());
-
-                renderState.meshState().bindQuadIndicesBuffer();
-
-                // If returns true, a VBO was bound and we must
-                // rebind our vertex attrib pointers even if
-                // they have the same values as the current pointers
-                forceRebind = renderState.meshState().unbindMeshBuffer();
-
-                caches.textureState().activateTexture(0);
-#endif
                 first = false;
                 mDrawn = true;
             }
-#if USE_GLOPS
+
             mFunctor->draw(*texture, mLinearFiltering);
-#endif
 
-#if !USE_GLOPS
-            caches.textureState().bindTexture(texture->getTextureId());
-            texture->setLinearFiltering(mLinearFiltering);
-
-            TextureVertex* mesh = texture->mesh();
-            MeshState& meshState = renderState.meshState();
-            meshState.bindPositionVertexPointer(forceRebind, &mesh[0].x);
-            meshState.bindTexCoordsVertexPointer(forceRebind, &mesh[0].u);
-
-            glDrawElements(GL_TRIANGLES, texture->meshElementCount(),
-                    GL_UNSIGNED_SHORT, texture->indices());
-#endif
             texture->resetMesh();
             forceRebind = false;
         }
@@ -689,7 +621,7 @@
     return image;
 }
 
-void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor) {
     checkInit();
 
     mDrawn = false;
@@ -717,7 +649,7 @@
 
 bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
-        const float* positions, Rect* bounds, TextSetupFunctor* functor, bool forceFinish) {
+        const float* positions, Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
@@ -735,7 +667,7 @@
 
 bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
-        float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor) {
+        float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 0603389..dfb107c 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -46,9 +46,9 @@
 
 class OpenGLRenderer;
 
-class TextSetupFunctor {
+class TextDrawFunctor {
 public:
-    TextSetupFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
+    TextDrawFunctor(OpenGLRenderer* renderer, float x, float y, bool pureTranslate,
             int alpha, SkXfermode::Mode mode, const SkPaint* paint)
         : renderer(renderer)
         , x(x)
@@ -59,8 +59,6 @@
         , paint(paint) {
     }
 
-    void setup(GLenum glyphFormat);
-
     void draw(CacheTexture& texture, bool linearFiltering);
 
     OpenGLRenderer* renderer;
@@ -92,12 +90,12 @@
     // bounds is an out parameter
     bool renderPosText(const SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y, const float* positions,
-            Rect* bounds, TextSetupFunctor* functor, bool forceFinish = true);
+            Rect* bounds, TextDrawFunctor* functor, bool forceFinish = true);
 
     // bounds is an out parameter
     bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const char *text,
             uint32_t startIndex, uint32_t len, int numGlyphs, const SkPath* path,
-            float hOffset, float vOffset, Rect* bounds, TextSetupFunctor* functor);
+            float hOffset, float vOffset, Rect* bounds, TextDrawFunctor* functor);
 
     struct DropShadow {
         uint32_t width;
@@ -135,7 +133,7 @@
     void flushAllAndInvalidate();
 
     void checkInit();
-    void initRender(const Rect* clip, Rect* bounds, TextSetupFunctor* functor);
+    void initRender(const Rect* clip, Rect* bounds, TextDrawFunctor* functor);
     void finishRender();
 
     void issueDrawCommand(Vector<CacheTexture*>& cacheTextures);
@@ -176,7 +174,7 @@
 
     bool mUploadTexture;
 
-    TextSetupFunctor* mFunctor;
+    TextDrawFunctor* mFunctor;
     const Rect* mClip;
     Rect* mBounds;
     bool mDrawn;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 0a46014..9ca6bc6 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -586,6 +586,12 @@
     mDescription.hasColors = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kColor;
     mDescription.hasVertexAlpha = mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::kAlpha;
 
+    // Enable debug highlight when what we're about to draw is tested against
+    // the stencil buffer and if stencil highlight debugging is on
+    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
+            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
+            && mRenderState.stencil().isTestEnabled();
+
     // serialize shader info into ShaderData
     GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
     SkiaShader::store(mCaches, mShader, mOutGlop->transform.modelView,
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 65be9e1..cc5c403 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -169,6 +169,10 @@
     newData->jankFrameCount += mData->jankFrameCount;
     newData->totalFrameCount >>= divider;
     newData->totalFrameCount += mData->totalFrameCount;
+    if (newData->statStartTime > mData->statStartTime
+            || newData->statStartTime == 0) {
+        newData->statStartTime = mData->statStartTime;
+    }
 
     freeData();
     mData = newData;
@@ -235,6 +239,7 @@
 }
 
 void JankTracker::dumpData(const ProfileData* data, int fd) {
+    dprintf(fd, "\nStats since: %" PRIu64 "ns", data->statStartTime);
     dprintf(fd, "\nTotal frames rendered: %u", data->totalFrameCount);
     dprintf(fd, "\nJanky frames: %u (%.2f%%)", data->jankFrameCount,
             (float) data->jankFrameCount / (float) data->totalFrameCount * 100.0f);
@@ -252,6 +257,7 @@
     mData->frameCounts.fill(0);
     mData->totalFrameCount = 0;
     mData->jankFrameCount = 0;
+    mData->statStartTime = systemTime(CLOCK_MONOTONIC);
 }
 
 uint32_t JankTracker::findPercentile(const ProfileData* data, int percentile) {
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index 4783001..3887e5e 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -44,10 +44,11 @@
 struct ProfileData {
     std::array<uint32_t, NUM_BUCKETS> jankTypeCounts;
     // See comments on kBucket* constants for what this holds
-    std::array<uint32_t, 57> frameCounts;
+    std::array<uint32_t, 55> frameCounts;
 
     uint32_t totalFrameCount;
     uint32_t jankFrameCount;
+    nsecs_t statStartTime;
 };
 
 // TODO: Replace DrawProfiler with this
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 02fbd89..aa722d0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -57,8 +57,6 @@
     #define EVENT_LOGD(...)
 #endif
 
-#define USE_GLOPS true
-
 namespace android {
 namespace uirenderer {
 
@@ -82,8 +80,6 @@
     // *set* draw modifiers to be 0
     memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
     mDrawModifiers.mOverrideLayerAlpha = 1.0f;
-
-    memcpy(mMeshVertices, kUnitQuadVertices, sizeof(kUnitQuadVertices));
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -846,124 +842,42 @@
 }
 
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
-    if (USE_GLOPS) {
-        bool snap = !layer->getForceFilter()
-                && layer->getWidth() == (uint32_t) rect.getWidth()
-                && layer->getHeight() == (uint32_t) rect.getHeight();
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
-                .setFillTextureLayer(*layer, getLayerAlpha(layer))
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewMapUnitToRectOptionalSnap(snap, rect)
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    float alpha = getLayerAlpha(layer);
-    setupDraw();
-    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
-        setupDrawWithTexture();
-    } else {
-        setupDrawWithExternalTexture();
-    }
-    setupDrawTextureTransform();
-    setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter(layer->getColorFilter());
-    setupDrawBlending(layer);
-    setupDrawProgram();
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(layer->getColorFilter());
-    if (layer->getRenderTarget() == GL_TEXTURE_2D) {
-        setupDrawTexture(layer->getTextureId());
-    } else {
-        setupDrawExternalTexture(layer->getTextureId());
-    }
-    if (currentTransform()->isPureTranslate()
-            && !layer->getForceFilter()
+    bool snap = !layer->getForceFilter()
             && layer->getWidth() == (uint32_t) rect.getWidth()
-            && layer->getHeight() == (uint32_t) rect.getHeight()) {
-        const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
-
-        layer->setFilter(GL_NEAREST);
-        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
-                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
-    } else {
-        layer->setFilter(GL_LINEAR);
-        setupDrawModelView(kModelViewMode_TranslateAndScale, false,
-                rect.left, rect.top, rect.right, rect.bottom);
-    }
-    setupDrawTextureTransformUniforms(layer->getTexTransform());
-    setupDrawMesh(&mMeshVertices[0].x, &mMeshVertices[0].u);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
+            && layer->getHeight() == (uint32_t) rect.getHeight();
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+            .setFillTextureLayer(*layer, getLayerAlpha(layer))
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
     if (layer->isTextureLayer()) {
         EVENT_LOGD("composeTextureLayerRect");
-        resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
         drawTextureLayer(layer, rect);
-        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
     } else {
         EVENT_LOGD("composeHardwareLayerRect");
 
-        if (USE_GLOPS) {
-            Blend::ModeOrderSwap modeUsage = swap ?
-                    Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap;
-            const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform();
-            bool snap = !swap
-                    && layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
-                    && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
-            Glop glop;
-            GlopBuilder(mRenderState, mCaches, &glop)
-                    .setMeshTexturedUvQuad(nullptr, layer->texCoords)
-                    .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage)
-                    .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
-                    .setModelViewMapUnitToRectOptionalSnap(snap, rect)
-                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                    .build();
-            renderGlop(glop);
-            return;
-        }
-
-        const Rect& texCoords = layer->texCoords;
-        resetDrawTextureTexCoords(texCoords.left, texCoords.top,
-                texCoords.right, texCoords.bottom);
-
-        float x = rect.left;
-        float y = rect.top;
-        bool simpleTransform = currentTransform()->isPureTranslate()
-                && layer->getWidth() == (uint32_t) rect.getWidth()
-                && layer->getHeight() == (uint32_t) rect.getHeight();
-
-        if (simpleTransform) {
-            // When we're swapping, the layer is already in screen coordinates
-            if (!swap) {
-                x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
-                y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
-            }
-
-            layer->setFilter(GL_NEAREST, true);
-        } else {
-            layer->setFilter(GL_LINEAR, true);
-        }
-
-        SkPaint layerPaint;
-        layerPaint.setAlpha(getLayerAlpha(layer) * 255);
-        layerPaint.setXfermodeMode(layer->getMode());
-        layerPaint.setColorFilter(layer->getColorFilter());
-
-        bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
-        drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
-                layer->getTextureId(), &layerPaint, blend,
-                &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
-
-        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+        Blend::ModeOrderSwap modeUsage = swap ?
+                Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap;
+        const Matrix4& transform = swap ? Matrix4::identity() : *currentTransform();
+        bool snap = !swap
+                && layer->getWidth() == static_cast<uint32_t>(rect.getWidth())
+                && layer->getHeight() == static_cast<uint32_t>(rect.getHeight());
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshTexturedUvQuad(nullptr, layer->texCoords)
+                .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), modeUsage)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setModelViewMapUnitToRectOptionalSnap(snap, rect)
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
     }
 }
 
@@ -1079,69 +993,8 @@
     const float texY = 1.0f / float(layer->getHeight());
     const float height = rect.getHeight();
 
-    if (USE_GLOPS) {
-        TextureVertex quadVertices[count * 4];
-        //std::unique_ptr<TextureVertex[]> quadVertices(new TextureVertex[count * 4]);
-        TextureVertex* mesh = &quadVertices[0];
-        for (size_t i = 0; i < count; i++) {
-            const android::Rect* r = &rects[i];
-
-            const float u1 = r->left * texX;
-            const float v1 = (height - r->top) * texY;
-            const float u2 = r->right * texX;
-            const float v2 = (height - r->bottom) * texY;
-
-            // TODO: Reject quads outside of the clip
-            TextureVertex::set(mesh++, r->left, r->top, u1, v1);
-            TextureVertex::set(mesh++, r->right, r->top, u2, v1);
-            TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
-            TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
-        }
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
-                .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewOffsetRectSnap(0, 0, rect)
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
-        return;
-    }
-
-    const float alpha = getLayerAlpha(layer);
-
-    setupDraw();
-
-    // We must get (and therefore bind) the region mesh buffer
-    // after we setup drawing in case we need to mess with the
-    // stencil buffer in setupDraw()
-    TextureVertex* mesh = mCaches.getRegionMesh();
-    uint32_t numQuads = 0;
-
-    setupDrawWithTexture();
-    setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter(layer->getColorFilter());
-    setupDrawBlending(layer);
-    setupDrawProgram();
-    setupDrawDirtyRegionsDisabled();
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(layer->getColorFilter());
-    setupDrawTexture(layer->getTextureId());
-    if (currentTransform()->isPureTranslate()) {
-        const float x = floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
-
-        layer->setFilter(GL_NEAREST);
-        setupDrawModelView(kModelViewMode_Translate, false,
-                x, y, x + rect.getWidth(), y + rect.getHeight(), true);
-    } else {
-        layer->setFilter(GL_LINEAR);
-        setupDrawModelView(kModelViewMode_Translate, false,
-                rect.left, rect.top, rect.right, rect.bottom);
-    }
-    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
-
+    TextureVertex quadVertices[count * 4];
+    TextureVertex* mesh = &quadVertices[0];
     for (size_t i = 0; i < count; i++) {
         const android::Rect* r = &rects[i];
 
@@ -1155,21 +1008,16 @@
         TextureVertex::set(mesh++, r->right, r->top, u2, v1);
         TextureVertex::set(mesh++, r->left, r->bottom, u1, v2);
         TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
-
-        numQuads++;
-
-        if (numQuads >= kMaxNumberOfQuads) {
-            DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
-                    GL_UNSIGNED_SHORT, nullptr));
-            numQuads = 0;
-            mesh = mCaches.getRegionMesh();
-        }
     }
-
-    if (numQuads > 0) {
-        DRAW_DOUBLE_STENCIL(glDrawElements(GL_TRIANGLES, numQuads * 6,
-                GL_UNSIGNED_SHORT, nullptr));
-    }
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedIndexedQuads(&quadVertices[0], count * 6)
+            .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewOffsetRectSnap(0, 0, rect)
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
 
 #if DEBUG_LAYERS_AS_REGIONS
     drawRegionRectsDebug(layer->region);
@@ -1248,21 +1096,6 @@
     }
 }
 
-void OpenGLRenderer::issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount) {
-    GLsizei elementsCount = quadsCount * 6;
-    while (elementsCount > 0) {
-        GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
-
-        setupDrawIndexedVertices(&mesh[0].x);
-        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr);
-
-        elementsCount -= drawCount;
-        // Though there are 4 vertices in a quad, we use 6 indices per
-        // quad to draw with GL_TRIANGLES
-        mesh += (drawCount / 6) * 4;
-    }
-}
-
 void OpenGLRenderer::clearLayerRegions() {
     const size_t quadCount = mLayers.size();
     if (quadCount == 0) return;
@@ -1290,34 +1123,19 @@
             Vertex::set(vertex++, bounds.right, bounds.bottom);
         }
         // We must clear the list of dirty rects before we
-        // call setupDraw() to prevent stencil setup to do
-        // the same thing again
+        // call clearLayerRegions() in renderGlop to prevent
+        // stencil setup from doing the same thing again
         mLayers.clear();
 
-        if (USE_GLOPS) {
-            Glop glop;
-            GlopBuilder(mRenderState, mCaches, &glop)
-                    .setMeshIndexedQuads(&mesh[0], quadCount)
-                    .setFillClear()
-                    .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
-                    .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
-                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                    .build();
-            renderGlop(glop, false);
-        } else {
-            SkPaint clearPaint;
-            clearPaint.setXfermodeMode(SkXfermode::kClear_Mode);
-
-            setupDraw(false);
-            setupDrawColor(0.0f, 0.0f, 0.0f, 1.0f);
-            setupDrawBlending(&clearPaint, true);
-            setupDrawProgram();
-            setupDrawPureColorUniforms();
-            setupDrawModelView(kModelViewMode_Translate, false,
-                    0.0f, 0.0f, 0.0f, 0.0f, true);
-
-            issueIndexedQuadDraw(&mesh[0], quadCount);
-        }
+        Glop glop;
+        GlopBuilder(mRenderState, mCaches, &glop)
+                .setMeshIndexedQuads(&mesh[0], quadCount)
+                .setFillClear()
+                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                .setModelViewOffsetRect(0, 0, Rect(currentSnapshot()->getClipRect()))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop, false);
 
         if (scissorChanged) mRenderState.scissor().setEnabled(true);
     } else {
@@ -1498,35 +1316,16 @@
     mRenderState.scissor().set(scissorBox.left, getViewportHeight() - scissorBox.bottom,
             scissorBox.getWidth(), scissorBox.getHeight());
 
-    if (USE_GLOPS) {
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshIndexedQuads(&rectangleVertices[0], rectangleVertices.size() / 4)
-                .setFillBlack()
-                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
-                .setModelViewOffsetRect(0, 0, scissorBox)
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    const SkPaint* paint = nullptr;
-    setupDraw();
-    setupDrawNoTexture();
-    setupDrawColor(0, 0xff * currentSnapshot()->alpha);
-    setupDrawShader(getShader(paint));
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawBlending(paint);
-    setupDrawProgram();
-    setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(kModelViewMode_Translate, false,
-            0.0f, 0.0f, 0.0f, 0.0f, true);
-    setupDrawColorUniforms(getShader(paint));
-    setupDrawShaderUniforms(getShader(paint));
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-
-    issueIndexedQuadDraw(&rectangleVertices[0], rectangleVertices.size() / 4);
+    Glop glop;
+    Vertex* vertices = &rectangleVertices[0];
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshIndexedQuads(vertices, rectangleVertices.size() / 4)
+            .setFillBlack()
+            .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+            .setModelViewOffsetRect(0, 0, scissorBox)
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::setStencilFromClip() {
@@ -1666,355 +1465,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-// Drawing commands
-///////////////////////////////////////////////////////////////////////////////
-
-void OpenGLRenderer::setupDraw(bool clearLayer) {
-    // TODO: It would be best if we could do this before quickRejectSetupScissor()
-    //       changes the scissor test state
-    if (clearLayer) clearLayerRegions();
-    // Make sure setScissor & setStencil happen at the beginning of
-    // this method
-    if (mState.getDirtyClip()) {
-        if (mRenderState.scissor().isEnabled()) {
-            setScissorFromClip();
-        }
-
-        setStencilFromClip();
-    }
-
-    mDescription.reset();
-
-    mSetShaderColor = false;
-    mColorSet = false;
-    mColor.a = mColor.r = mColor.g = mColor.b = 0.0f;
-    mTextureUnit = 0;
-    mTrackDirtyRegions = true;
-
-    // Enable debug highlight when what we're about to draw is tested against
-    // the stencil buffer and if stencil highlight debugging is on
-    mDescription.hasDebugHighlight = !mCaches.debugOverdraw
-            && mCaches.debugStencilClip == Caches::kStencilShowHighlight
-            && mRenderState.stencil().isTestEnabled();
-}
-
-void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) {
-    mDescription.hasTexture = true;
-    mDescription.hasAlpha8Texture = isAlpha8;
-}
-
-void OpenGLRenderer::setupDrawWithTextureAndColor(bool isAlpha8) {
-    mDescription.hasTexture = true;
-    mDescription.hasColors = true;
-    mDescription.hasAlpha8Texture = isAlpha8;
-}
-
-void OpenGLRenderer::setupDrawWithExternalTexture() {
-    mDescription.hasExternalTexture = true;
-}
-
-void OpenGLRenderer::setupDrawNoTexture() {
-    mRenderState.meshState().disableTexCoordsVertexArray();
-}
-
-void OpenGLRenderer::setupDrawVertexAlpha(bool useShadowAlphaInterp) {
-    mDescription.hasVertexAlpha = true;
-    mDescription.useShadowAlphaInterp = useShadowAlphaInterp;
-}
-
-void OpenGLRenderer::setupDrawColor(int color, int alpha) {
-    mColor.a = alpha / 255.0f;
-    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
-    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
-    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
-    mColorSet = true;
-    mSetShaderColor = mDescription.setColorModulate(mColor.a);
-}
-
-void OpenGLRenderer::setupDrawAlpha8Color(int color, int alpha) {
-    mColor.a = alpha / 255.0f;
-    mColor.r = mColor.a * ((color >> 16) & 0xFF) / 255.0f;
-    mColor.g = mColor.a * ((color >>  8) & 0xFF) / 255.0f;
-    mColor.b = mColor.a * ((color      ) & 0xFF) / 255.0f;
-    mColorSet = true;
-    mSetShaderColor = mDescription.setAlpha8ColorModulate(mColor.r, mColor.g, mColor.b, mColor.a);
-}
-
-void OpenGLRenderer::setupDrawTextGamma(const SkPaint* paint) {
-    mCaches.fontRenderer->describe(mDescription, paint);
-}
-
-void OpenGLRenderer::setupDrawColor(float r, float g, float b, float a) {
-    mColor.a = a;
-    mColor.r = r;
-    mColor.g = g;
-    mColor.b = b;
-    mColorSet = true;
-    mSetShaderColor = mDescription.setColorModulate(a);
-}
-
-void OpenGLRenderer::setupDrawShader(const SkShader* shader) {
-    if (shader != nullptr) {
-        SkiaShader::describe(&mCaches, mDescription, mCaches.extensions(), *shader);
-    }
-}
-
-void OpenGLRenderer::setupDrawColorFilter(const SkColorFilter* filter) {
-    if (filter == nullptr) {
-        return;
-    }
-
-    SkXfermode::Mode mode;
-    if (filter->asColorMode(nullptr, &mode)) {
-        mDescription.colorOp = ProgramDescription::kColorBlend;
-        mDescription.colorMode = mode;
-    } else if (filter->asColorMatrix(nullptr)) {
-        mDescription.colorOp = ProgramDescription::kColorMatrix;
-    }
-}
-
-void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) {
-    if (mColorSet && mode == SkXfermode::kClear_Mode) {
-        mColor.a = 1.0f;
-        mColor.r = mColor.g = mColor.b = 0.0f;
-        mSetShaderColor = mDescription.modulate = true;
-    }
-}
-
-void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) {
-    SkXfermode::Mode mode = layer->getMode();
-    // When the blending mode is kClear_Mode, we need to use a modulate color
-    // argb=1,0,0,0
-    accountForClear(mode);
-    // TODO: check shader blending, once we have shader drawing support for layers.
-    bool blend = layer->isBlend()
-            || getLayerAlpha(layer) < 1.0f
-            || (mColorSet && mColor.a < 1.0f)
-            || PaintUtils::isBlendedColorFilter(layer->getColorFilter());
-    chooseBlending(blend, mode, mDescription, swapSrcDst);
-}
-
-void OpenGLRenderer::setupDrawBlending(const SkPaint* paint, bool blend, bool swapSrcDst) {
-    SkXfermode::Mode mode = getXfermodeDirect(paint);
-    // When the blending mode is kClear_Mode, we need to use a modulate color
-    // argb=1,0,0,0
-    accountForClear(mode);
-    blend |= (mColorSet && mColor.a < 1.0f)
-            || (getShader(paint) && !getShader(paint)->isOpaque())
-            || PaintUtils::isBlendedColorFilter(getColorFilter(paint));
-    chooseBlending(blend, mode, mDescription, swapSrcDst);
-}
-
-void OpenGLRenderer::setupDrawProgram() {
-    mCaches.setProgram(mDescription);
-    if (mDescription.hasRoundRectClip) {
-        // TODO: avoid doing this repeatedly, stashing state pointer in program
-        const RoundRectClipState* state = writableSnapshot()->roundRectClipState;
-        const Rect& innerRect = state->innerRect;
-        glUniform4f(mCaches.program().getUniform("roundRectInnerRectLTRB"),
-                innerRect.left, innerRect.top,
-                innerRect.right, innerRect.bottom);
-        glUniformMatrix4fv(mCaches.program().getUniform("roundRectInvTransform"),
-                1, GL_FALSE, &state->matrix.data[0]);
-
-        // add half pixel to round out integer rect space to cover pixel centers
-        float roundedOutRadius = state->radius + 0.5f;
-        glUniform1f(mCaches.program().getUniform("roundRectRadius"),
-                roundedOutRadius);
-    }
-}
-
-void OpenGLRenderer::setupDrawDirtyRegionsDisabled() {
-    mTrackDirtyRegions = false;
-}
-
-void OpenGLRenderer::setupDrawModelView(ModelViewMode mode, bool offset,
-        float left, float top, float right, float bottom, bool ignoreTransform) {
-    mModelViewMatrix.loadTranslate(left, top, 0.0f);
-    if (mode == kModelViewMode_TranslateAndScale) {
-        mModelViewMatrix.scale(right - left, bottom - top, 1.0f);
-    }
-
-    bool dirty = right - left > 0.0f && bottom - top > 0.0f;
-    const Matrix4& transformMatrix = ignoreTransform ? Matrix4::identity() : *currentTransform();
-
-    mCaches.program().set(currentSnapshot()->getOrthoMatrix(),
-            mModelViewMatrix, transformMatrix, offset);
-    if (dirty && mTrackDirtyRegions) {
-        if (!ignoreTransform) {
-            dirtyLayer(left, top, right, bottom, *currentTransform());
-        } else {
-            dirtyLayer(left, top, right, bottom);
-        }
-    }
-}
-
-void OpenGLRenderer::setupDrawColorUniforms(bool hasShader) {
-    if ((mColorSet && !hasShader) || (hasShader && mSetShaderColor)) {
-        mCaches.program().setColor(mColor);
-    }
-}
-
-void OpenGLRenderer::setupDrawPureColorUniforms() {
-    if (mSetShaderColor) {
-        mCaches.program().setColor(mColor);
-    }
-}
-
-void OpenGLRenderer::setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform) {
-    if (shader == nullptr) {
-        return;
-    }
-
-    if (ignoreTransform) {
-        // if ignoreTransform=true was passed to setupDrawModelView, undo currentTransform()
-        // because it was built into modelView / the geometry, and the description needs to
-        // compensate.
-        mat4 modelViewWithoutTransform;
-        modelViewWithoutTransform.loadInverse(*currentTransform());
-        modelViewWithoutTransform.multiply(mModelViewMatrix);
-        mModelViewMatrix.load(modelViewWithoutTransform);
-    }
-
-    SkiaShader::setupProgram(&mCaches, mModelViewMatrix, &mTextureUnit,
-            mCaches.extensions(), *shader);
-}
-
-void OpenGLRenderer::setupDrawColorFilterUniforms(const SkColorFilter* filter) {
-    if (nullptr == filter) {
-        return;
-    }
-
-    SkColor color;
-    SkXfermode::Mode mode;
-    if (filter->asColorMode(&color, &mode)) {
-        const int alpha = SkColorGetA(color);
-        const GLfloat a = alpha / 255.0f;
-        const GLfloat r = a * SkColorGetR(color) / 255.0f;
-        const GLfloat g = a * SkColorGetG(color) / 255.0f;
-        const GLfloat b = a * SkColorGetB(color) / 255.0f;
-        glUniform4f(mCaches.program().getUniform("colorBlend"), r, g, b, a);
-        return;
-    }
-
-    SkScalar srcColorMatrix[20];
-    if (filter->asColorMatrix(srcColorMatrix)) {
-
-        float colorMatrix[16];
-        memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
-        memcpy(&colorMatrix[4], &srcColorMatrix[5], 4 * sizeof(float));
-        memcpy(&colorMatrix[8], &srcColorMatrix[10], 4 * sizeof(float));
-        memcpy(&colorMatrix[12], &srcColorMatrix[15], 4 * sizeof(float));
-
-        // Skia uses the range [0..255] for the addition vector, but we need
-        // the [0..1] range to apply the vector in GLSL
-        float colorVector[4];
-        colorVector[0] = srcColorMatrix[4] / 255.0f;
-        colorVector[1] = srcColorMatrix[9] / 255.0f;
-        colorVector[2] = srcColorMatrix[14] / 255.0f;
-        colorVector[3] = srcColorMatrix[19] / 255.0f;
-
-        glUniformMatrix4fv(mCaches.program().getUniform("colorMatrix"), 1,
-                GL_FALSE, colorMatrix);
-        glUniform4fv(mCaches.program().getUniform("colorMatrixVector"), 1, colorVector);
-        return;
-    }
-
-    // it is an error if we ever get here
-}
-
-void OpenGLRenderer::setupDrawTextGammaUniforms() {
-    mCaches.fontRenderer->setupProgram(mDescription, mCaches.program());
-}
-
-void OpenGLRenderer::setupDrawSimpleMesh() {
-    bool force = mRenderState.meshState().bindMeshBuffer();
-    mRenderState.meshState().bindPositionVertexPointer(force, nullptr);
-    mRenderState.meshState().unbindIndicesBuffer();
-}
-
-void OpenGLRenderer::setupDrawTexture(GLuint texture) {
-    if (texture) mCaches.textureState().bindTexture(texture);
-    mTextureUnit++;
-    mRenderState.meshState().enableTexCoordsVertexArray();
-}
-
-void OpenGLRenderer::setupDrawExternalTexture(GLuint texture) {
-    mCaches.textureState().bindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
-    mTextureUnit++;
-    mRenderState.meshState().enableTexCoordsVertexArray();
-}
-
-void OpenGLRenderer::setupDrawTextureTransform() {
-    mDescription.hasTextureTransform = true;
-}
-
-void OpenGLRenderer::setupDrawTextureTransformUniforms(mat4& transform) {
-    glUniformMatrix4fv(mCaches.program().getUniform("mainTextureTransform"), 1,
-            GL_FALSE, &transform.data[0]);
-}
-
-void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
-        const GLvoid* texCoords, GLuint vbo) {
-    bool force = false;
-    if (!vertices || vbo) {
-        force = mRenderState.meshState().bindMeshBuffer(vbo);
-    } else {
-        force = mRenderState.meshState().unbindMeshBuffer();
-    }
-
-    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
-    if (mCaches.program().texCoords >= 0) {
-        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
-    }
-
-    mRenderState.meshState().unbindIndicesBuffer();
-}
-
-void OpenGLRenderer::setupDrawMesh(const GLvoid* vertices,
-        const GLvoid* texCoords, const GLvoid* colors) {
-    bool force = mRenderState.meshState().unbindMeshBuffer();
-    GLsizei stride = sizeof(ColorTextureVertex);
-
-    mRenderState.meshState().bindPositionVertexPointer(force, vertices, stride);
-    if (mCaches.program().texCoords >= 0) {
-        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords, stride);
-    }
-    int slot = mCaches.program().getAttrib("colors");
-    if (slot >= 0) {
-        glEnableVertexAttribArray(slot);
-        glVertexAttribPointer(slot, 4, GL_FLOAT, GL_FALSE, stride, colors);
-    }
-
-    mRenderState.meshState().unbindIndicesBuffer();
-}
-
-void OpenGLRenderer::setupDrawMeshIndices(const GLvoid* vertices,
-        const GLvoid* texCoords, GLuint vbo) {
-    bool force = false;
-    // If vbo is != 0 we want to treat the vertices parameter as an offset inside
-    // a VBO. However, if vertices is set to NULL and vbo == 0 then we want to
-    // use the default VBO found in RenderState
-    if (!vertices || vbo) {
-        force = mRenderState.meshState().bindMeshBuffer(vbo);
-    } else {
-        force = mRenderState.meshState().unbindMeshBuffer();
-    }
-    mRenderState.meshState().bindQuadIndicesBuffer();
-
-    mRenderState.meshState().bindPositionVertexPointer(force, vertices);
-    if (mCaches.program().texCoords >= 0) {
-        mRenderState.meshState().bindTexCoordsVertexPointer(force, texCoords);
-    }
-}
-
-void OpenGLRenderer::setupDrawIndexedVertices(GLvoid* vertices) {
-    bool force = mRenderState.meshState().unbindMeshBuffer();
-    mRenderState.meshState().bindQuadIndicesBuffer();
-    mRenderState.meshState().bindPositionVertexPointer(force, vertices, kVertexStride);
-}
-
-///////////////////////////////////////////////////////////////////////////////
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -2049,30 +1499,6 @@
     }
 }
 
-void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
-    float x = 0;
-    float y = 0;
-
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-
-    bool ignoreTransform = false;
-    if (currentTransform()->isPureTranslate()) {
-        x = floorf(currentTransform()->getTranslateX() + 0.5f);
-        y = floorf(currentTransform()->getTranslateY() + 0.5f);
-        ignoreTransform = true;
-
-        texture->setFilter(GL_NEAREST, true);
-    } else {
-        texture->setFilter(PaintUtils::getFilter(paint), true);
-    }
-
-    // No need to check for a UV mapper on the texture object, only ARGB_8888
-    // bitmaps get packed in the atlas
-    drawAlpha8TextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-            paint, (GLvoid*) nullptr, (GLvoid*) kMeshTextureOffset,
-            GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
-}
-
 /**
  * Important note: this method is intended to draw batches of bitmaps and
  * will not set the scissor enable or dirty the current layer, if any.
@@ -2086,45 +1512,22 @@
 
     const AutoTexture autoCleanup(texture);
 
-    if (USE_GLOPS) {
-        // TODO: remove layer dirty in multi-draw callers
-        // TODO: snap doesn't need to touch transform, only texture filter.
-        bool snap = pureTranslate;
-        const float x = floorf(bounds.left + 0.5f);
-        const float y = floorf(bounds.top + 0.5f);
-        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
-                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedMesh(vertices, bitmapCount * 6)
-                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
-                .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    mCaches.textureState().activateTexture(0);
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(pureTranslate ? GL_NEAREST : PaintUtils::getFilter(paint), true);
-
+    // TODO: remove layer dirty in multi-draw callers
+    // TODO: snap doesn't need to touch transform, only texture filter.
+    bool snap = pureTranslate;
     const float x = floorf(bounds.left + 0.5f);
     const float y = floorf(bounds.top + 0.5f);
-    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlpha8TextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
-                texture->id, paint, &vertices[0].x, &vertices[0].u,
-                GL_TRIANGLES, bitmapCount * 6, true,
-                kModelViewMode_Translate, false);
-    } else {
-        drawTextureMesh(x, y, x + bounds.getWidth(), y + bounds.getHeight(),
-                texture->id, paint, texture->blend, &vertices[0].x, &vertices[0].u,
-                GL_TRIANGLES, bitmapCount * 6, false, true, 0,
-                kModelViewMode_Translate, false);
-    }
-
-    mDirty = true;
+    int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
+            ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedMesh(vertices, bitmapCount * 6)
+            .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+            .setModelViewOffsetRectOptionalSnap(snap, x, y, Rect(0, 0, bounds.getWidth(), bounds.getHeight()))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
@@ -2137,28 +1540,17 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (USE_GLOPS) {
-        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
-                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedUnitQuad(texture->uvMapper)
-                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlphaBitmap(texture, paint);
-    } else {
-        drawTextureRect(texture, paint);
-    }
-
-    mDirty = true;
+    int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
+            ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedUnitQuad(texture->uvMapper)
+            .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::drawBitmapMesh(const SkBitmap* bitmap, int meshWidth, int meshHeight,
@@ -2235,56 +1627,19 @@
     }
     const AutoTexture autoCleanup(texture);
 
-    if (USE_GLOPS) {
-        /*
-         * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
-         * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
-         */
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshColoredTexturedMesh(mesh.get(), elementCount)
-                .setFillTexturePaint(*texture, static_cast<int>(TextureFillFlags::kNone), paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    mCaches.textureState().activateTexture(0);
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(PaintUtils::getFilter(paint), true);
-
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-
-    dirtyLayer(left, top, right, bottom, *currentTransform());
-
-    float a = alpha / 255.0f;
-    setupDraw();
-    setupDrawWithTextureAndColor();
-    setupDrawColor(a, a, a, a);
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawBlending(paint, true);
-    setupDrawProgram();
-    setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(kModelViewMode_Translate, false, 0, 0, 0, 0);
-    setupDrawTexture(texture->id);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawMesh(&mesh[0].x, &mesh[0].u, &mesh[0].r);
-
-    glDrawArrays(GL_TRIANGLES, 0, elementCount);
-
-    int slot = mCaches.program().getAttrib("colors");
-    if (slot >= 0) {
-        glDisableVertexAttribArray(slot);
-    }
-
-    mDirty = true;
+    /*
+     * TODO: handle alpha_8 textures correctly by applying paint color, but *not*
+     * shader in that case to mimic the behavior in SkiaCanvas::drawBitmapMesh.
+     */
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshColoredTexturedMesh(mesh.get(), elementCount)
+            .setFillTexturePaint(*texture, static_cast<int>(TextureFillFlags::kNone), paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, Rect src, Rect dst, const SkPaint* paint) {
@@ -2296,80 +1651,22 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (USE_GLOPS) {
-        Rect uv(fmax(0.0f, src.left / texture->width),
-                fmax(0.0f, src.top / texture->height),
-                fmin(1.0f, src.right / texture->width),
-                fmin(1.0f, src.bottom / texture->height));
+    Rect uv(fmax(0.0f, src.left / texture->width),
+            fmax(0.0f, src.top / texture->height),
+            fmin(1.0f, src.right / texture->width),
+            fmin(1.0f, src.bottom / texture->height));
 
-        int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
-                ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedUvQuad(texture->uvMapper, uv)
-                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewMapUnitToRectSnap(dst)
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    mCaches.textureState().activateTexture(0);
-
-    const float width = texture->width;
-    const float height = texture->height;
-
-    float u1 = fmax(0.0f, src.left / width);
-    float v1 = fmax(0.0f, src.top / height);
-    float u2 = fmin(1.0f, src.right / width);
-    float v2 = fmin(1.0f, src.bottom / height);
-
-    getMapper(texture).map(u1, v1, u2, v2);
-
-    mRenderState.meshState().unbindMeshBuffer();
-    resetDrawTextureTexCoords(u1, v1, u2, v2);
-
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-
-    float scaleX = (dst.right - dst.left) / (src.right - src.left);
-    float scaleY = (dst.bottom - dst.top) / (src.bottom - src.top);
-
-    bool scaled = scaleX != 1.0f || scaleY != 1.0f;
-    bool ignoreTransform = false;
-
-    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-        float x = floorf(dst.left + currentTransform()->getTranslateX() + 0.5f);
-        float y = floorf(dst.top + currentTransform()->getTranslateY() + 0.5f);
-
-        dst.right = x + (dst.right - dst.left);
-        dst.bottom = y + (dst.bottom - dst.top);
-
-        dst.left = x;
-        dst.top = y;
-
-        texture->setFilter(scaled ? PaintUtils::getFilter(paint) : GL_NEAREST, true);
-        ignoreTransform = true;
-    } else {
-        texture->setFilter(PaintUtils::getFilter(paint), true);
-    }
-
-    if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
-        drawAlpha8TextureMesh(dst.left, dst.top, dst.right, dst.bottom,
-                texture->id, paint,
-                &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, kUnitQuadCount, ignoreTransform);
-    } else {
-        drawTextureMesh(dst.left, dst.top, dst.right, dst.bottom,
-                texture->id, paint, texture->blend,
-                &mMeshVertices[0].x, &mMeshVertices[0].u,
-                GL_TRIANGLE_STRIP, kUnitQuadCount, false, ignoreTransform);
-    }
-
-    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
-
-    mDirty = true;
+    int textureFillFlags = static_cast<int>((bitmap->colorType() == kAlpha_8_SkColorType)
+            ? TextureFillFlags::kIsAlphaMaskTexture : TextureFillFlags::kNone);
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedUvQuad(texture->uvMapper, uv)
+            .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewMapUnitToRectSnap(dst)
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::drawPatch(const SkBitmap* bitmap, const Patch* mesh,
@@ -2382,66 +1679,20 @@
     Texture* texture = entry ? entry->texture : mCaches.textureCache.get(bitmap);
     if (!texture) return;
 
-    if (USE_GLOPS) {
-        // 9 patches are built for stretching - always filter
-        int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
-        if (bitmap->colorType() == kAlpha_8_SkColorType) {
-            textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
-        }
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshPatchQuads(*mesh)
-                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
+    // 9 patches are built for stretching - always filter
+    int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
+    if (bitmap->colorType() == kAlpha_8_SkColorType) {
+        textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
     }
-
-    mCaches.textureState().activateTexture(0);
-    const AutoTexture autoCleanup(texture);
-
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(GL_LINEAR, true);
-
-    const bool pureTranslate = currentTransform()->isPureTranslate();
-    // Mark the current layer dirty where we are going to draw the patch
-    if (hasLayer() && mesh->hasEmptyQuads) {
-        const float offsetX = left + currentTransform()->getTranslateX();
-        const float offsetY = top + currentTransform()->getTranslateY();
-        const size_t count = mesh->quads.size();
-        for (size_t i = 0; i < count; i++) {
-            const Rect& bounds = mesh->quads.itemAt(i);
-            if (CC_LIKELY(pureTranslate)) {
-                const float x = floorf(bounds.left + offsetX + 0.5f);
-                const float y = floorf(bounds.top + offsetY + 0.5f);
-                dirtyLayer(x, y, x + bounds.getWidth(), y + bounds.getHeight());
-            } else {
-                dirtyLayer(left + bounds.left, top + bounds.top,
-                        left + bounds.right, top + bounds.bottom, *currentTransform());
-            }
-        }
-    }
-
-    bool ignoreTransform = false;
-    if (CC_LIKELY(pureTranslate)) {
-        const float x = floorf(left + currentTransform()->getTranslateX() + 0.5f);
-        const float y = floorf(top + currentTransform()->getTranslateY() + 0.5f);
-
-        right = x + right - left;
-        bottom = y + bottom - top;
-        left = x;
-        top = y;
-        ignoreTransform = true;
-    }
-    drawIndexedTextureMesh(left, top, right, bottom, texture->id, paint,
-            texture->blend, (GLvoid*) mesh->positionOffset, (GLvoid*) mesh->textureOffset,
-            GL_TRIANGLES, mesh->indexCount, false, ignoreTransform,
-            mCaches.patchCache.getMeshBuffer(), kModelViewMode_Translate, !mesh->hasEmptyQuads);
-
-    mDirty = true;
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshPatchQuads(*mesh)
+            .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewOffsetRectSnap(left, top, Rect(0, 0, right - left, bottom - top)) // TODO: get minimal bounds from patch
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 /**
@@ -2456,33 +1707,21 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
-    if (USE_GLOPS) {
-        // TODO: get correct bounds from caller
-        // 9 patches are built for stretching - always filter
-        int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
-        if (bitmap->colorType() == kAlpha_8_SkColorType) {
-            textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
-        }
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedIndexedQuads(vertices, elementCount)
-                .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
-                .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
+    // TODO: get correct bounds from caller
+    // 9 patches are built for stretching - always filter
+    int textureFillFlags = static_cast<int>(TextureFillFlags::kForceFilter);
+    if (bitmap->colorType() == kAlpha_8_SkColorType) {
+        textureFillFlags |= TextureFillFlags::kIsAlphaMaskTexture;
     }
-
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(GL_LINEAR, true);
-
-    drawIndexedTextureMesh(0.0f, 0.0f, 1.0f, 1.0f, texture->id, paint,
-            texture->blend, &vertices[0].x, &vertices[0].u,
-            GL_TRIANGLES, elementCount, false, true, 0, kModelViewMode_Translate, false);
-
-    mDirty = true;
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedIndexedQuads(vertices, elementCount)
+            .setFillTexturePaint(*texture, textureFillFlags, paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+            .setModelViewOffsetRect(0, 0, Rect(0, 0, 0, 0))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::drawVertexBuffer(float translateX, float translateY,
@@ -2493,72 +1732,17 @@
         return;
     }
 
-    if (USE_GLOPS) {
-        bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
-        bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshVertexBuffer(vertexBuffer, shadowInterp)
-                .setFillPaint(*paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
-                .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    const VertexBuffer::MeshFeatureFlags meshFeatureFlags = vertexBuffer.getMeshFeatureFlags();
-    Rect bounds(vertexBuffer.getBounds());
-    bounds.translate(translateX, translateY);
-    dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
-
-    int color = paint->getColor();
-    bool isAA = meshFeatureFlags & VertexBuffer::kAlpha;
-
-    setupDraw();
-    setupDrawNoTexture();
-    if (isAA) setupDrawVertexAlpha((displayFlags & kVertexBuffer_ShadowInterp));
-    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader(getShader(paint));
-    setupDrawBlending(paint, isAA);
-    setupDrawProgram();
-    setupDrawModelView(kModelViewMode_Translate, (displayFlags & kVertexBuffer_Offset),
-            translateX, translateY, 0, 0);
-    setupDrawColorUniforms(getShader(paint));
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms(getShader(paint));
-
-    const void* vertices = vertexBuffer.getBuffer();
-    mRenderState.meshState().unbindMeshBuffer();
-    mRenderState.meshState().bindPositionVertexPointer(true, vertices,
-            isAA ? kAlphaVertexStride : kVertexStride);
-    mRenderState.meshState().resetTexCoordsVertexPointer();
-
-    int alphaSlot = -1;
-    if (isAA) {
-        void* alphaCoords = ((GLbyte*) vertices) + kVertexAlphaOffset;
-        alphaSlot = mCaches.program().getAttrib("vtxAlpha");
-        // TODO: avoid enable/disable in back to back uses of the alpha attribute
-        glEnableVertexAttribArray(alphaSlot);
-        glVertexAttribPointer(alphaSlot, 1, GL_FLOAT, GL_FALSE, kAlphaVertexStride, alphaCoords);
-    }
-
-    if (meshFeatureFlags & VertexBuffer::kIndices) {
-        mRenderState.meshState().unbindIndicesBuffer();
-        glDrawElements(GL_TRIANGLE_STRIP, vertexBuffer.getIndexCount(),
-                GL_UNSIGNED_SHORT, vertexBuffer.getIndices());
-    } else {
-        mRenderState.meshState().unbindIndicesBuffer();
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexBuffer.getVertexCount());
-    }
-
-    if (isAA) {
-        glDisableVertexAttribArray(alphaSlot);
-    }
-
-    mDirty = true;
+    bool fudgeOffset = displayFlags & kVertexBuffer_Offset;
+    bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshVertexBuffer(vertexBuffer, shadowInterp)
+            .setFillPaint(*paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
+            .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 /**
@@ -2813,40 +1997,15 @@
     const float sx = x - texture->left + textShadow.dx;
     const float sy = y - texture->top + textShadow.dy;
 
-    if (USE_GLOPS) {
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedUnitQuad(nullptr)
-                .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    const int shadowAlpha = ((textShadow.color >> 24) & 0xFF) * currentSnapshot()->alpha;
-    if (getShader(paint)) {
-        textShadow.color = SK_ColorWHITE;
-    }
-
-    setupDraw();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(textShadow.color, shadowAlpha < 255 ? shadowAlpha : alpha);
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader(getShader(paint));
-    setupDrawBlending(paint, true);
-    setupDrawProgram();
-    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
-            sx, sy, sx + texture->width, sy + texture->height);
-    setupDrawTexture(texture->id);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms(getShader(paint));
-    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedUnitQuad(nullptr)
+            .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
@@ -2898,7 +2057,7 @@
     const Rect& clip(pureTranslate ? writableSnapshot()->getClipRect() : writableSnapshot()->getLocalClip());
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
-    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
+    TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
     if (fontRenderer.renderPosText(paint, &clip, text, 0, bytesCount, count, x, y,
             positions, hasLayer() ? &bounds : nullptr, &functor)) {
         dirtyLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, *currentTransform());
@@ -3050,7 +2209,7 @@
     Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
-    TextSetupFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
+    TextDrawFunctor functor(this, x, y, pureTranslate, alpha, mode, paint);
 
     // don't call issuedrawcommand, do it at end of batch
     bool forceFinish = (drawOpMode != DrawOpMode::kDefer);
@@ -3092,7 +2251,7 @@
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
-    TextSetupFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
+    TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
 
     const Rect* clip = &writableSnapshot()->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
@@ -3159,56 +2318,15 @@
             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
                     composeLayerRect(layer, layer->regionRect));
         } else if (layer->mesh) {
-            if (USE_GLOPS) {
-                Glop glop;
-                GlopBuilder(mRenderState, mCaches, &glop)
-                        .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
-                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
-                        .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                        .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
-                        .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                        .build();
-                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
-            } else {
-                const float a = getLayerAlpha(layer);
-                setupDraw();
-                setupDrawWithTexture();
-                setupDrawColor(a, a, a, a);
-                setupDrawColorFilter(layer->getColorFilter());
-                setupDrawBlending(layer);
-                setupDrawProgram();
-                setupDrawPureColorUniforms();
-                setupDrawColorFilterUniforms(layer->getColorFilter());
-                setupDrawTexture(layer->getTextureId());
-                if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-                    int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
-                    int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
-
-                    layer->setFilter(GL_NEAREST);
-                    setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
-                            tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
-                } else {
-                    layer->setFilter(GL_LINEAR);
-                    setupDrawModelView(kModelViewMode_Translate, false, x, y,
-                            x + layer->layer.getWidth(), y + layer->layer.getHeight());
-                }
-
-                TextureVertex* mesh = &layer->mesh[0];
-                GLsizei elementsCount = layer->meshElementCount;
-
-                while (elementsCount > 0) {
-                    GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
-
-                    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
-                    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
-                            glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
-
-                    elementsCount -= drawCount;
-                    // Though there are 4 vertices in a quad, we use 6 indices per
-                    // quad to draw with GL_TRIANGLES
-                    mesh += (drawCount / 6) * 4;
-                }
-            }
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
+                    .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
+                    .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                    .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+                    .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                    .build();
+            DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
 #if DEBUG_LAYERS_AS_REGIONS
             drawRegionRectsDebug(layer->region);
 #endif
@@ -3258,40 +2376,15 @@
         return;
     }
 
-    if (USE_GLOPS) {
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshTexturedUnitQuad(nullptr)
-                .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
-                .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    setupDraw();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader(getShader(paint));
-    setupDrawBlending(paint, true);
-    setupDrawProgram();
-    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
-            x, y, x + texture->width, y + texture->height);
-    setupDrawTexture(texture->id);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms(getShader(paint));
-    setupDrawMesh(nullptr, (GLvoid*) kMeshTextureOffset);
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshTexturedUnitQuad(nullptr)
+            .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+            .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 // Same values used by Skia
@@ -3419,249 +2512,30 @@
         return;
     }
 
-    if (USE_GLOPS) {
-        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshIndexedQuads(&mesh[0], count / 4)
-                .setFillPaint(*paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
-                .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    int color = paint->getColor();
-    // If a shader is set, preserve only the alpha
-    if (getShader(paint)) {
-        color |= 0x00ffffff;
-    }
-
-    setupDraw();
-    setupDrawNoTexture();
-    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
-    setupDrawShader(getShader(paint));
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawBlending(paint);
-    setupDrawProgram();
-    setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(kModelViewMode_Translate, false,
-            0.0f, 0.0f, 0.0f, 0.0f, ignoreTransform);
-    setupDrawColorUniforms(getShader(paint));
-    setupDrawShaderUniforms(getShader(paint));
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-
-    if (dirty && hasLayer()) {
-        dirtyLayer(left, top, right, bottom, *currentTransform());
-    }
-
-    issueIndexedQuadDraw(&mesh[0], count / 4);
-
-    mDirty = true;
+    const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshIndexedQuads(&mesh[0], count / 4)
+            .setFillPaint(*paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+            .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
         const SkPaint* paint, bool ignoreTransform) {
-
-    if (USE_GLOPS) {
-        const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
-        Glop glop;
-        GlopBuilder(mRenderState, mCaches, &glop)
-                .setMeshUnitQuad()
-                .setFillPaint(*paint, currentSnapshot()->alpha)
-                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
-                .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
-                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
-                .build();
-        renderGlop(glop);
-        return;
-    }
-
-    int color = paint->getColor();
-    // If a shader is set, preserve only the alpha
-    if (getShader(paint)) {
-        color |= 0x00ffffff;
-    }
-
-    setupDraw();
-    setupDrawNoTexture();
-    setupDrawColor(color, ((color >> 24) & 0xFF) * currentSnapshot()->alpha);
-    setupDrawShader(getShader(paint));
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawBlending(paint);
-    setupDrawProgram();
-    setupDrawModelView(kModelViewMode_TranslateAndScale, false,
-            left, top, right, bottom, ignoreTransform);
-    setupDrawColorUniforms(getShader(paint));
-    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawSimpleMesh();
-
-    glDrawArrays(GL_TRIANGLE_STRIP, 0, kUnitQuadCount);
-}
-
-void OpenGLRenderer::drawTextureRect(Texture* texture, const SkPaint* paint) {
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-
-    GLvoid* vertices = (GLvoid*) nullptr;
-    GLvoid* texCoords = (GLvoid*) kMeshTextureOffset;
-
-    if (texture->uvMapper) {
-        vertices = &mMeshVertices[0].x;
-        texCoords = &mMeshVertices[0].u;
-
-        Rect uvs(0.0f, 0.0f, 1.0f, 1.0f);
-        texture->uvMapper->map(uvs);
-
-        resetDrawTextureTexCoords(uvs.left, uvs.top, uvs.right, uvs.bottom);
-    }
-
-    if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-        const float x = floorf(currentTransform()->getTranslateX() + 0.5f);
-        const float y = floorf(currentTransform()->getTranslateY() + 0.5f);
-
-        texture->setFilter(GL_NEAREST, true);
-        drawTextureMesh(x, y, x + texture->width, y + texture->height, texture->id,
-                paint, texture->blend, vertices, texCoords,
-                GL_TRIANGLE_STRIP, kUnitQuadCount, false, true);
-    } else {
-        texture->setFilter(PaintUtils::getFilter(paint), true);
-        drawTextureMesh(0, 0, texture->width, texture->height, texture->id, paint,
-                texture->blend, vertices, texCoords, GL_TRIANGLE_STRIP, kUnitQuadCount);
-    }
-
-    if (texture->uvMapper) {
-        resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
-    }
-}
-
-void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float bottom,
-        GLuint texture, const SkPaint* paint, bool blend,
-        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
-        ModelViewMode modelViewMode, bool dirty) {
-
-    int a;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &a, &mode);
-    const float alpha = a / 255.0f;
-
-    setupDraw();
-    setupDrawWithTexture();
-    setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawBlending(paint, blend, swapSrcDst);
-    setupDrawProgram();
-    if (!dirty) setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
-    setupDrawTexture(texture);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawMesh(vertices, texCoords, vbo);
-
-    glDrawArrays(drawMode, 0, elementsCount);
-}
-
-void OpenGLRenderer::drawIndexedTextureMesh(float left, float top, float right, float bottom,
-        GLuint texture, const SkPaint* paint, bool blend,
-        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool swapSrcDst, bool ignoreTransform, GLuint vbo,
-        ModelViewMode modelViewMode, bool dirty) {
-
-    int a;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &a, &mode);
-    const float alpha = a / 255.0f;
-
-    setupDraw();
-    setupDrawWithTexture();
-    setupDrawColor(alpha, alpha, alpha, alpha);
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawBlending(paint, blend, swapSrcDst);
-    setupDrawProgram();
-    if (!dirty) setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
-    setupDrawTexture(texture);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawMeshIndices(vertices, texCoords, vbo);
-
-    glDrawElements(drawMode, elementsCount, GL_UNSIGNED_SHORT, nullptr);
-}
-
-void OpenGLRenderer::drawAlpha8TextureMesh(float left, float top, float right, float bottom,
-        GLuint texture, const SkPaint* paint,
-        GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-        bool ignoreTransform, ModelViewMode modelViewMode, bool dirty) {
-
-    int color = paint != nullptr ? paint->getColor() : 0;
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    setupDraw();
-    setupDrawWithTexture(true);
-    if (paint != nullptr) {
-        setupDrawAlpha8Color(color, alpha);
-    }
-    setupDrawColorFilter(getColorFilter(paint));
-    setupDrawShader(getShader(paint));
-    setupDrawBlending(paint, true);
-    setupDrawProgram();
-    if (!dirty) setupDrawDirtyRegionsDisabled();
-    setupDrawModelView(modelViewMode, false, left, top, right, bottom, ignoreTransform);
-    setupDrawTexture(texture);
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms(getColorFilter(paint));
-    setupDrawShaderUniforms(getShader(paint), ignoreTransform);
-    setupDrawMesh(vertices, texCoords);
-
-    glDrawArrays(drawMode, 0, elementsCount);
-}
-
-void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode,
-        ProgramDescription& description, bool swapSrcDst) {
-
-    if (currentSnapshot()->roundRectClipState != nullptr /*&& !mSkipOutlineClip*/) {
-        blend = true;
-        mDescription.hasRoundRectClip = true;
-    }
-    mSkipOutlineClip = true;
-
-    blend = blend || mode != SkXfermode::kSrcOver_Mode;
-
-    if (blend) {
-        // These blend modes are not supported by OpenGL directly and have
-        // to be implemented using shaders. Since the shader will perform
-        // the blending, turn blending off here
-        // If the blend mode cannot be implemented using shaders, fall
-        // back to the default SrcOver blend mode instead
-        if (CC_UNLIKELY(mode > SkXfermode::kScreen_Mode)) {
-            if (CC_UNLIKELY(mCaches.extensions().hasFramebufferFetch())) {
-                description.framebufferMode = mode;
-                description.swapSrcDst = swapSrcDst;
-
-                mRenderState.blend().disable();
-                return;
-            } else {
-                mode = SkXfermode::kSrcOver_Mode;
-            }
-        }
-        mRenderState.blend().enable(mode,
-                swapSrcDst ? Blend::ModeOrderSwap::Swap : Blend::ModeOrderSwap::NoSwap);
-    } else {
-        mRenderState.blend().disable();
-    }
-}
-
-void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
-    TextureVertex* v = &mMeshVertices[0];
-    TextureVertex::setUV(v++, u1, v1);
-    TextureVertex::setUV(v++, u2, v1);
-    TextureVertex::setUV(v++, u1, v2);
-    TextureVertex::setUV(v++, u2, v2);
+    const Matrix4& transform = ignoreTransform ? Matrix4::identity() : *currentTransform();
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setMeshUnitQuad()
+            .setFillPaint(*paint, currentSnapshot()->alpha)
+            .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
+            .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
+            .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+            .build();
+    renderGlop(glop);
 }
 
 void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f4acad0..5f8960a 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -65,7 +65,7 @@
 struct Glop;
 class RenderState;
 class RenderNode;
-class TextSetupFunctor;
+class TextDrawFunctor;
 class VertexBuffer;
 
 struct DrawModifiers {
@@ -727,15 +727,6 @@
     void drawShape(float left, float top, PathTexture* texture, const SkPaint* paint);
 
     /**
-     * Draws the specified texture as an alpha bitmap. Alpha bitmaps obey
-     * different compositing rules.
-     *
-     * @param texture The texture to draw with
-     * @param paint The paint to render with
-     */
-    void drawAlphaBitmap(Texture* texture, const SkPaint* paint);
-
-    /**
      * Renders a strip of polygons with the specified paint, used for tessellated geometry.
      *
      * @param vertexBuffer The VertexBuffer to be drawn
@@ -762,60 +753,6 @@
     void drawConvexPath(const SkPath& path, const SkPaint* paint);
 
     /**
-     * Draws a textured rectangle with the specified texture.
-     *
-     * @param texture The texture to use
-     * @param paint The paint containing the alpha, blending mode, etc.
-     */
-    void drawTextureRect(Texture* texture, const SkPaint* paint);
-
-    /**
-     * Draws a textured mesh with the specified texture. If the indices are omitted,
-     * the mesh is drawn as a simple quad. The mesh pointers become offsets when a
-     * VBO is bound.
-     *
-     * @param left The left coordinate of the rectangle
-     * @param top The top coordinate of the rectangle
-     * @param right The right coordinate of the rectangle
-     * @param bottom The bottom coordinate of the rectangle
-     * @param texture The texture name to map onto the rectangle
-     * @param paint The paint containing the alpha, blending mode, colorFilter, etc.
-     * @param blend True if the texture contains an alpha channel
-     * @param vertices The vertices that define the mesh
-     * @param texCoords The texture coordinates of each vertex
-     * @param elementsCount The number of elements in the mesh, required by indices
-     * @param swapSrcDst Whether or not the src and dst blending operations should be swapped
-     * @param ignoreTransform True if the current transform should be ignored
-     * @param vbo The VBO used to draw the mesh
-     * @param modelViewMode Defines whether the model view matrix should be scaled
-     * @param dirty True if calling this method should dirty the current layer
-     */
-    void drawTextureMesh(float left, float top, float right, float bottom, GLuint texture,
-            const SkPaint* paint, bool blend,
-            GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-            bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
-            ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
-
-    void drawIndexedTextureMesh(float left, float top, float right, float bottom, GLuint texture,
-            const SkPaint* paint, bool blend,
-            GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-            bool swapSrcDst = false, bool ignoreTransform = false, GLuint vbo = 0,
-            ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale, bool dirty = true);
-
-    void drawAlpha8TextureMesh(float left, float top, float right, float bottom,
-            GLuint texture, const SkPaint* paint,
-            GLvoid* vertices, GLvoid* texCoords, GLenum drawMode, GLsizei elementsCount,
-            bool ignoreTransform, ModelViewMode modelViewMode = kModelViewMode_TranslateAndScale,
-            bool dirty = true);
-
-    /**
-     * Draws the specified list of vertices as quads using indexed GL_TRIANGLES.
-     * If the number of vertices to draw exceeds the number of indices we have
-     * pre-allocated, this method will generate several glDrawElements() calls.
-     */
-    void issueIndexedQuadDraw(Vertex* mesh, GLsizei quadsCount);
-
-    /**
      * Draws text underline and strike-through if needed.
      *
      * @param text The text to decor
@@ -873,78 +810,6 @@
      */
     bool canSkipText(const SkPaint* paint) const;
 
-    /**
-     * Enable or disable blending as necessary. This function sets the appropriate
-     * blend function based on the specified xfermode.
-     */
-    inline void chooseBlending(bool blend, SkXfermode::Mode mode, ProgramDescription& description,
-            bool swapSrcDst = false);
-
-    /**
-     * Invoked before any drawing operation. This sets required state.
-     */
-    void setupDraw(bool clear = true);
-
-    /**
-     * Various methods to setup OpenGL rendering.
-     */
-    void setupDrawWithTexture(bool isAlpha8 = false);
-    void setupDrawWithTextureAndColor(bool isAlpha8 = false);
-    void setupDrawWithExternalTexture();
-    void setupDrawNoTexture();
-    void setupDrawVertexAlpha(bool useShadowAlphaInterp);
-    void setupDrawColor(int color, int alpha);
-    void setupDrawColor(float r, float g, float b, float a);
-    void setupDrawAlpha8Color(int color, int alpha);
-    void setupDrawTextGamma(const SkPaint* paint);
-    void setupDrawShader(const SkShader* shader);
-    void setupDrawColorFilter(const SkColorFilter* filter);
-    void setupDrawBlending(const Layer* layer, bool swapSrcDst = false);
-    void setupDrawBlending(const SkPaint* paint, bool blend = true, bool swapSrcDst = false);
-    void setupDrawProgram();
-    void setupDrawDirtyRegionsDisabled();
-
-    /**
-     * Setup the current program matrices based upon the nature of the geometry.
-     *
-     * @param mode If kModelViewMode_Translate, the geometry must be translated by the left and top
-     * parameters. If kModelViewMode_TranslateAndScale, the geometry that exists in the (0,0, 1,1)
-     * space must be scaled up and translated to fill the quad provided in (l,t,r,b). These
-     * transformations are stored in the modelView matrix and uploaded to the shader.
-     *
-     * @param offset Set to true if the the matrix should be fudged (translated) slightly to
-     * disambiguate geometry pixel positioning. See Vertex::GeometryFudgeFactor().
-     *
-     * @param ignoreTransform Set to true if l,t,r,b coordinates already in layer space,
-     * currentTransform() will be ignored. (e.g. when drawing clip in layer coordinates to stencil,
-     * or when simple translation has been extracted)
-     */
-    void setupDrawModelView(ModelViewMode mode, bool offset,
-            float left, float top, float right, float bottom, bool ignoreTransform = false);
-    void setupDrawColorUniforms(bool hasShader);
-    void setupDrawPureColorUniforms();
-
-    /**
-     * Setup uniforms for the current shader.
-     *
-     * @param shader SkShader on the current paint.
-     *
-     * @param ignoreTransform Set to true to ignore the transform in shader.
-     */
-    void setupDrawShaderUniforms(const SkShader* shader, bool ignoreTransform = false);
-    void setupDrawColorFilterUniforms(const SkColorFilter* paint);
-    void setupDrawSimpleMesh();
-    void setupDrawTexture(GLuint texture);
-    void setupDrawExternalTexture(GLuint texture);
-    void setupDrawTextureTransform();
-    void setupDrawTextureTransformUniforms(mat4& transform);
-    void setupDrawTextGammaUniforms();
-    void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords = nullptr, GLuint vbo = 0);
-    void setupDrawMesh(const GLvoid* vertices, const GLvoid* texCoords, const GLvoid* colors);
-    void setupDrawMeshIndices(const GLvoid* vertices, const GLvoid* texCoords, GLuint vbo = 0);
-    void setupDrawIndexedVertices(GLvoid* vertices);
-    void accountForClear(SkXfermode::Mode mode);
-
     bool updateLayer(Layer* layer, bool inFrame);
     void updateLayers();
     void flushLayers();
@@ -993,22 +858,6 @@
     inline Snapshot* writableSnapshot() { return mState.writableSnapshot(); }
     inline const Snapshot* currentSnapshot() const { return mState.currentSnapshot(); }
 
-    /**
-     * Model-view matrix used to position/size objects
-     *
-     * Stores operation-local modifications to the draw matrix that aren't incorporated into the
-     * currentTransform().
-     *
-     * If generated with kModelViewMode_Translate, mModelViewMatrix will reflect an x/y offset,
-     * e.g. the offset in drawLayer(). If generated with kModelViewMode_TranslateAndScale,
-     * mModelViewMatrix will reflect a translation and scale, e.g. the translation and scale
-     * required to make VBO 0 (a rect of (0,0,1,1)) scaled to match the x,y offset, and width/height
-     * of a bitmap.
-     *
-     * Used as input to SkiaShader transformation.
-     */
-    mat4 mModelViewMatrix;
-
     // State used to define the clipping region
     Rect mTilingClip;
     // Is the target render surface opaque
@@ -1016,9 +865,6 @@
     // Is a frame currently being rendered
     bool mFrameStarted;
 
-    // Used to draw textured quads
-    TextureVertex mMeshVertices[4];
-
     // Default UV mapper
     const UvMapper mUvMapper;
 
@@ -1031,21 +877,6 @@
     // List of layers to update at the beginning of a frame
     Vector< sp<Layer> > mLayerUpdates;
 
-    // The following fields are used to setup drawing
-    // Used to describe the shaders to generate
-    ProgramDescription mDescription;
-    // Color description
-    bool mColorSet;
-    FloatColor mColor;
-    // Indicates that the shader should get a color
-    bool mSetShaderColor;
-    // Current texture unit
-    GLuint mTextureUnit;
-    // Track dirty regions, true by default
-    bool mTrackDirtyRegions;
-    // Indicate whether we are drawing an opaque frame
-    bool mOpaqueFrame;
-
     // See PROPERTY_DISABLE_SCISSOR_OPTIMIZATION in
     // Properties.h
     bool mScissorOptimizationDisabled;
@@ -1070,7 +901,7 @@
     std::vector<std::unique_ptr<SkPath>> mTempPaths;
 
     friend class Layer;
-    friend class TextSetupFunctor;
+    friend class TextDrawFunctor;
     friend class DrawBitmapOp;
     friend class DrawPatchOp;
 
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index e9b22e2..41adda1 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -240,8 +240,9 @@
 const char* gFS_Main_ApplyVertexAlphaLinearInterp =
         "    fragColor *= alpha;\n";
 const char* gFS_Main_ApplyVertexAlphaShadowInterp =
-        "    fragColor *= (1.0 - cos(alpha)) / 2.0;\n";
-
+        // Use a gaussian function for the shadow fall off. Note that alpha here
+        // is actually (1.0 - alpha) for saving computation.
+        "    fragColor *= exp(- alpha * alpha * 4.0) - 0.018;\n";
 const char* gFS_Main_FetchTexture[2] = {
         // Don't modulate
         "    fragColor = texture2D(baseSampler, outTexCoords);\n",
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 0380c51..d0812c9 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -158,6 +158,11 @@
                 buffer->getWidth(), buffer->getHeight());
 
         return true;
+    } else {
+        RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
+        RenderBuffer::formatName(buffer->getFormat()),
+                 buffer->getWidth(), buffer->getHeight(), size, mMaxSize);
+        delete buffer;
     }
     return false;
 }
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 2fcf7f3..ecf8b6b 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -47,15 +47,6 @@
     return !(n & (n - 1));
 }
 
-static inline void bindUniformColor(int slot, uint32_t color) {
-    const float a = ((color >> 24) & 0xff) / 255.0f;
-    glUniform4f(slot,
-            a * ((color >> 16) & 0xff) / 255.0f,
-            a * ((color >>  8) & 0xff) / 255.0f,
-            a * ((color      ) & 0xff) / 255.0f,
-            a);
-}
-
 static inline void bindUniformColor(int slot, FloatColor color) {
     glUniform4fv(slot, 1, reinterpret_cast<const float*>(&color));
 }
@@ -83,229 +74,11 @@
     screenSpace.multiply(modelViewMatrix);
 }
 
-// Returns true if one is a bitmap and the other is a gradient
-static bool bitmapAndGradient(SkiaShaderType type1, SkiaShaderType type2) {
-    return (type1 == kBitmap_SkiaShaderType && type2 == kGradient_SkiaShaderType)
-            || (type2 == kBitmap_SkiaShaderType && type1 == kGradient_SkiaShaderType);
-}
-
-SkiaShaderType SkiaShader::getType(const SkShader& shader) {
-    // First check for a gradient shader.
-    switch (shader.asAGradient(nullptr)) {
-        case SkShader::kNone_GradientType:
-            // Not a gradient shader. Fall through to check for other types.
-            break;
-        case SkShader::kLinear_GradientType:
-        case SkShader::kRadial_GradientType:
-        case SkShader::kSweep_GradientType:
-            return kGradient_SkiaShaderType;
-        default:
-            // This is a Skia gradient that has no SkiaShader equivalent. Return None to skip.
-            return kNone_SkiaShaderType;
-    }
-
-    // The shader is not a gradient. Check for a bitmap shader.
-    if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
-        return kBitmap_SkiaShaderType;
-    }
-
-    // Check for a ComposeShader.
-    SkShader::ComposeRec rec;
-    if (shader.asACompose(&rec)) {
-        const SkiaShaderType shaderAType = getType(*rec.fShaderA);
-        const SkiaShaderType shaderBType = getType(*rec.fShaderB);
-
-        // Compose is only supported if one is a bitmap and the other is a
-        // gradient. Otherwise, return None to skip.
-        if (!bitmapAndGradient(shaderAType, shaderBType)) {
-            return kNone_SkiaShaderType;
-        }
-        return kCompose_SkiaShaderType;
-    }
-
-    if (shader.asACustomShader(nullptr)) {
-        return kLayer_SkiaShaderType;
-    }
-
-    return kNone_SkiaShaderType;
-}
-
-typedef void (*describeProc)(Caches* caches, ProgramDescription& description,
-        const Extensions& extensions, const SkShader& shader);
-
-describeProc gDescribeProc[] = {
-    InvalidSkiaShader::describe,
-    SkiaBitmapShader::describe,
-    SkiaGradientShader::describe,
-    SkiaComposeShader::describe,
-    SkiaLayerShader::describe,
-};
-
-typedef void (*setupProgramProc)(Caches* caches, const mat4& modelViewMatrix,
-        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
-
-setupProgramProc gSetupProgramProc[] = {
-    InvalidSkiaShader::setupProgram,
-    SkiaBitmapShader::setupProgram,
-    SkiaGradientShader::setupProgram,
-    SkiaComposeShader::setupProgram,
-    SkiaLayerShader::setupProgram,
-};
-
-void SkiaShader::describe(Caches* caches, ProgramDescription& description,
-        const Extensions& extensions, const SkShader& shader) {
-    gDescribeProc[getType(shader)](caches, description, extensions, shader);
-}
-
-void SkiaShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
-        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
-
-    gSetupProgramProc[getType(shader)](caches, modelViewMatrix, textureUnit, extensions, shader);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
-// Layer shader
+// gradient shader matrix helpers
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkiaLayerShader::describe(Caches*, ProgramDescription& description,
-        const Extensions&, const SkShader& shader) {
-    description.hasBitmap = true;
-}
-
-void SkiaLayerShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
-        GLuint* textureUnit, const Extensions&, const SkShader& shader) {
-    Layer* layer;
-    if (!shader.asACustomShader(reinterpret_cast<void**>(&layer))) {
-        LOG_ALWAYS_FATAL("SkiaLayerShader::setupProgram called on the wrong type of shader!");
-    }
-
-    GLuint textureSlot = (*textureUnit)++;
-    caches->textureState().activateTexture(textureSlot);
-
-    const float width = layer->getWidth();
-    const float height = layer->getHeight();
-
-    mat4 textureTransform;
-    computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
-            modelViewMatrix);
-
-
-    // Uniforms
-    layer->bindTexture();
-    layer->setWrap(GL_CLAMP_TO_EDGE);
-    layer->setFilter(GL_LINEAR);
-
-    Program& program = caches->program();
-    glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
-    glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
-            GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program.getUniform("textureDimension"), 1.0f / width, 1.0f / height);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Bitmap shader
-///////////////////////////////////////////////////////////////////////////////
-
-struct BitmapShaderInfo {
-    float width;
-    float height;
-    GLenum wrapS;
-    GLenum wrapT;
-    Texture* texture;
-};
-
-static bool bitmapShaderHelper(Caches* caches, ProgramDescription* description,
-        BitmapShaderInfo* shaderInfo,
-        const Extensions& extensions,
-        const SkBitmap& bitmap, SkShader::TileMode tileModes[2]) {
-    Texture* texture = caches->textureCache.get(&bitmap);
-    if (!texture) return false;
-
-    const float width = texture->width;
-    const float height = texture->height;
-    GLenum wrapS, wrapT;
-
-    if (description) {
-        description->hasBitmap = true;
-    }
-    // The driver does not support non-power of two mirrored/repeated
-    // textures, so do it ourselves
-    if (!extensions.hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
-            (tileModes[0] != SkShader::kClamp_TileMode ||
-             tileModes[1] != SkShader::kClamp_TileMode)) {
-        if (description) {
-            description->isBitmapNpot = true;
-            description->bitmapWrapS = gTileModes[tileModes[0]];
-            description->bitmapWrapT = gTileModes[tileModes[1]];
-        }
-        wrapS = GL_CLAMP_TO_EDGE;
-        wrapT = GL_CLAMP_TO_EDGE;
-    } else {
-        wrapS = gTileModes[tileModes[0]];
-        wrapT = gTileModes[tileModes[1]];
-    }
-
-    if (shaderInfo) {
-        shaderInfo->width = width;
-        shaderInfo->height = height;
-        shaderInfo->wrapS = wrapS;
-        shaderInfo->wrapT = wrapT;
-        shaderInfo->texture = texture;
-    }
-    return true;
-}
-
-void SkiaBitmapShader::describe(Caches* caches, ProgramDescription& description,
-        const Extensions& extensions, const SkShader& shader) {
-    SkBitmap bitmap;
-    SkShader::TileMode xy[2];
-    if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
-        LOG_ALWAYS_FATAL("SkiaBitmapShader::describe called with a different kind of shader!");
-    }
-    bitmapShaderHelper(caches, &description, nullptr, extensions, bitmap, xy);
-}
-
-void SkiaBitmapShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
-        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
-    SkBitmap bitmap;
-    SkShader::TileMode xy[2];
-    if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
-        LOG_ALWAYS_FATAL("SkiaBitmapShader::setupProgram called with a different kind of shader!");
-    }
-
-    GLuint textureSlot = (*textureUnit)++;
-    caches->textureState().activateTexture(textureSlot);
-
-    BitmapShaderInfo shaderInfo;
-    if (!bitmapShaderHelper(caches, nullptr, &shaderInfo, extensions, bitmap, xy)) {
-        return;
-    }
-
-    Program& program = caches->program();
-    Texture* texture = shaderInfo.texture;
-
-    const AutoTexture autoCleanup(texture);
-
-    mat4 textureTransform;
-    computeScreenSpaceMatrix(textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
-            modelViewMatrix);
-
-    // Uniforms
-    bindTexture(caches, texture, shaderInfo.wrapS, shaderInfo.wrapT);
-    texture->setFilter(GL_LINEAR);
-
-    glUniform1i(program.getUniform("bitmapSampler"), textureSlot);
-    glUniformMatrix4fv(program.getUniform("textureTransform"), 1,
-            GL_FALSE, &textureTransform.data[0]);
-    glUniform2f(program.getUniform("textureDimension"), 1.0f / shaderInfo.width,
-            1.0f / shaderInfo.height);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Linear gradient shader
-///////////////////////////////////////////////////////////////////////////////
-
-static void toUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
+static void toLinearUnitMatrix(const SkPoint pts[2], SkMatrix* matrix) {
     SkVector vec = pts[1] - pts[0];
     const float mag = vec.length();
     const float inv = mag ? 1.0f / mag : 0;
@@ -316,10 +89,6 @@
     matrix->postScale(inv, inv);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Circular gradient shader
-///////////////////////////////////////////////////////////////////////////////
-
 static void toCircularUnitMatrix(const float x, const float y, const float radius,
         SkMatrix* matrix) {
     const float inv = 1.0f / radius;
@@ -327,10 +96,6 @@
     matrix->postScale(inv, inv);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Sweep gradient shader
-///////////////////////////////////////////////////////////////////////////////
-
 static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
     matrix->setTranslate(-x, -y);
 }
@@ -343,137 +108,6 @@
     return gradInfo.fColorCount == 2 && gradInfo.fTileMode == SkShader::kClamp_TileMode;
 }
 
-void SkiaGradientShader::describe(Caches*, ProgramDescription& description,
-        const Extensions& extensions, const SkShader& shader) {
-    SkShader::GradientInfo gradInfo;
-    gradInfo.fColorCount = 0;
-    gradInfo.fColors = nullptr;
-    gradInfo.fColorOffsets = nullptr;
-
-    switch (shader.asAGradient(&gradInfo)) {
-        case SkShader::kLinear_GradientType:
-            description.gradientType = ProgramDescription::kGradientLinear;
-            break;
-        case SkShader::kRadial_GradientType:
-            description.gradientType = ProgramDescription::kGradientCircular;
-            break;
-        case SkShader::kSweep_GradientType:
-            description.gradientType = ProgramDescription::kGradientSweep;
-            break;
-        default:
-            // Do nothing. This shader is unsupported.
-            return;
-    }
-    description.hasGradient = true;
-    description.isSimpleGradient = isSimpleGradient(gradInfo);
-}
-
-void SkiaGradientShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
-        GLuint* textureUnit, const Extensions&, const SkShader& shader) {
-    // SkShader::GradientInfo.fColorCount is an in/out parameter. As input, it tells asAGradient
-    // how much space has been allocated for fColors and fColorOffsets.  10 was chosen
-    // arbitrarily, but should be >= 2.
-    // As output, it tells the number of actual colors/offsets in the gradient.
-    const int COLOR_COUNT = 10;
-    SkAutoSTMalloc<COLOR_COUNT, SkColor> colorStorage(COLOR_COUNT);
-    SkAutoSTMalloc<COLOR_COUNT, SkScalar> positionStorage(COLOR_COUNT);
-
-    SkShader::GradientInfo gradInfo;
-    gradInfo.fColorCount = COLOR_COUNT;
-    gradInfo.fColors = colorStorage.get();
-    gradInfo.fColorOffsets = positionStorage.get();
-
-    SkShader::GradientType gradType = shader.asAGradient(&gradInfo);
-
-    Program& program = caches->program();
-    if (CC_UNLIKELY(!isSimpleGradient(gradInfo))) {
-        if (gradInfo.fColorCount > COLOR_COUNT) {
-            // There was not enough room in our arrays for all the colors and offsets. Try again,
-            // now that we know the true number of colors.
-            gradInfo.fColors = colorStorage.reset(gradInfo.fColorCount);
-            gradInfo.fColorOffsets = positionStorage.reset(gradInfo.fColorCount);
-
-            shader.asAGradient(&gradInfo);
-        }
-        GLuint textureSlot = (*textureUnit)++;
-        caches->textureState().activateTexture(textureSlot);
-
-#ifndef SK_SCALAR_IS_FLOAT
-    #error Need to convert gradInfo.fColorOffsets to float!
-#endif
-        Texture* texture = caches->gradientCache.get(gradInfo.fColors, gradInfo.fColorOffsets,
-                gradInfo.fColorCount);
-
-        // Uniforms
-        bindTexture(caches, texture, gTileModes[gradInfo.fTileMode], gTileModes[gradInfo.fTileMode]);
-        glUniform1i(program.getUniform("gradientSampler"), textureSlot);
-    } else {
-        bindUniformColor(program.getUniform("startColor"), gradInfo.fColors[0]);
-        bindUniformColor(program.getUniform("endColor"), gradInfo.fColors[1]);
-    }
-
-    caches->dither.setupProgram(program, textureUnit);
-
-    SkMatrix unitMatrix;
-    switch (gradType) {
-        case SkShader::kLinear_GradientType:
-            toUnitMatrix(gradInfo.fPoint, &unitMatrix);
-            break;
-        case SkShader::kRadial_GradientType:
-            toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
-                    gradInfo.fRadius[0], &unitMatrix);
-            break;
-        case SkShader::kSweep_GradientType:
-            toSweepUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, &unitMatrix);
-            break;
-        default:
-            LOG_ALWAYS_FATAL("Invalid SkShader gradient type %d", gradType);
-    }
-
-    mat4 screenSpace;
-    computeScreenSpaceMatrix(screenSpace, unitMatrix, shader.getLocalMatrix(), modelViewMatrix);
-    glUniformMatrix4fv(program.getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Compose shader
-///////////////////////////////////////////////////////////////////////////////
-
-void SkiaComposeShader::describe(Caches* caches, ProgramDescription& description,
-        const Extensions& extensions, const SkShader& shader) {
-    SkShader::ComposeRec rec;
-    if (!shader.asACompose(&rec)) {
-        LOG_ALWAYS_FATAL("SkiaComposeShader::describe called on the wrong shader type!");
-    }
-    SkiaShader::describe(caches, description, extensions, *rec.fShaderA);
-    SkiaShader::describe(caches, description, extensions, *rec.fShaderB);
-    if (SkiaShader::getType(*rec.fShaderA) == kBitmap_SkiaShaderType) {
-        description.isBitmapFirst = true;
-    }
-    if (!SkXfermode::AsMode(rec.fMode, &description.shadersMode)) {
-        // TODO: Support other modes.
-        description.shadersMode = SkXfermode::kSrcOver_Mode;
-    }
-}
-
-void SkiaComposeShader::setupProgram(Caches* caches, const mat4& modelViewMatrix,
-        GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
-    SkShader::ComposeRec rec;
-    if (!shader.asACompose(&rec)) {
-        LOG_ALWAYS_FATAL("SkiaComposeShader::setupProgram called on the wrong shader type!");
-    }
-
-    // Apply this compose shader's local transform and pass it down to
-    // the child shaders. They will in turn apply their local transform
-    // to this matrix.
-    mat4 transform;
-    computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(),
-            modelViewMatrix);
-
-    SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderA);
-    SkiaShader::setupProgram(caches, transform, textureUnit, extensions, *rec.fShaderB);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Store / apply
 ///////////////////////////////////////////////////////////////////////////////
@@ -491,7 +125,7 @@
         case SkShader::kLinear_GradientType:
             description->gradientType = ProgramDescription::kGradientLinear;
 
-            toUnitMatrix(gradInfo.fPoint, &unitMatrix);
+            toLinearUnitMatrix(gradInfo.fPoint, &unitMatrix);
             break;
         case SkShader::kRadial_GradientType:
             description->gradientType = ProgramDescription::kGradientCircular;
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 2962441c..5b8aa86 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -87,77 +87,12 @@
 
 class SkiaShader {
 public:
-    static SkiaShaderType getType(const SkShader& shader);
-    static void describe(Caches* caches, ProgramDescription& description,
-            const Extensions& extensions, const SkShader& shader);
-    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
-            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
-
-    // new SkiaShader interaction model - store into ShaderData, and apply to Caches/Program/GL
     static void store(Caches& caches, const SkShader* shader, const Matrix4& modelViewMatrix,
             GLuint* textureUnit, ProgramDescription* description,
             SkiaShaderData* outData);
     static void apply(Caches& caches, const SkiaShaderData& data);
 };
 
-class InvalidSkiaShader {
-public:
-    static void describe(Caches* caches, ProgramDescription& description,
-            const Extensions& extensions, const SkShader& shader) {
-        // This shader is unsupported. Skip it.
-    }
-    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
-            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader) {
-        // This shader is unsupported. Skip it.
-    }
-
-};
-/**
- * A shader that draws a layer.
- */
-class SkiaLayerShader {
-public:
-    static void describe(Caches* caches, ProgramDescription& description,
-            const Extensions& extensions, const SkShader& shader);
-    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
-            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
-}; // class SkiaLayerShader
-
-/**
- * A shader that draws a bitmap.
- */
-class SkiaBitmapShader {
-public:
-    static void describe(Caches* caches, ProgramDescription& description,
-            const Extensions& extensions, const SkShader& shader);
-    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
-            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
-
-
-}; // class SkiaBitmapShader
-
-/**
- * A shader that draws one of three types of gradient, depending on shader param.
- */
-class SkiaGradientShader {
-public:
-    static void describe(Caches* caches, ProgramDescription& description,
-            const Extensions& extensions, const SkShader& shader);
-    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
-            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
-};
-
-/**
- * A shader that draws two shaders, composited with an xfermode.
- */
-class SkiaComposeShader {
-public:
-    static void describe(Caches* caches, ProgramDescription& description,
-            const Extensions& extensions, const SkShader& shader);
-    static void setupProgram(Caches* caches, const mat4& modelViewMatrix,
-            GLuint* textureUnit, const Extensions& extensions, const SkShader& shader);
-}; // class SkiaComposeShader
-
 }; // namespace uirenderer
 }; // namespace android
 
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 597d95c..9e7faee 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -203,8 +203,9 @@
     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
             this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
     const Rect& clipRect(mClipArea->getClipRect());
-    ALOGD("  ClipRect %.1f %.1f %.1f %.1f",
-            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+    ALOGD("  ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
+            clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
+
     ALOGD("  Transform (at %p):", transform);
     transform->dump();
 }
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index b3b06d6..db3c2d9 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -44,6 +44,9 @@
 // For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
 #define SPOT_CORNER_RADIANS_DIVISOR (M_PI / SPOT_EXTRA_CORNER_VERTEX_PER_PI)
 
+// For performance, we use (1 - alpha) value for the shader input.
+#define TRANSFORMED_PENUMBRA_ALPHA 1.0f
+#define TRANSFORMED_UMBRA_ALPHA 0.0f
 
 #include <math.h>
 #include <stdlib.h>
@@ -964,11 +967,11 @@
     // Fill the IB and VB for the penumbra area.
     for (int i = 0; i < newPenumbraLength; i++) {
         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
-                newPenumbra[i].y, 0.0f);
+                newPenumbra[i].y, TRANSFORMED_PENUMBRA_ALPHA);
     }
     for (int i = 0; i < umbraLength; i++) {
         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
-                M_PI);
+                TRANSFORMED_UMBRA_ALPHA);
     }
 
     for (int i = 0; i < verticesPairIndex; i++) {
@@ -1008,14 +1011,14 @@
             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
             indexBuffer[indexBufferIndex++] = vertexBufferIndex;
             AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
-                    closerVertex.x, closerVertex.y, M_PI);
+                    closerVertex.x, closerVertex.y, TRANSFORMED_UMBRA_ALPHA);
         }
     } else {
         // If there is no occluded umbra at all, then draw the triangle fan
         // starting from the centroid to all umbra vertices.
         int lastCentroidIndex = vertexBufferIndex;
         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
-                centroid.y, M_PI);
+                centroid.y, TRANSFORMED_UMBRA_ALPHA);
         for (int i = 0; i < umbraLength; i++) {
             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
             indexBuffer[indexBufferIndex++] = lastCentroidIndex;
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
index 5600aeb..aa4a860 100644
--- a/location/java/android/location/FusedBatchOptions.java
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -30,6 +30,8 @@
 
     // the default value is set to request fixes at no cost
     private volatile double mMaxPowerAllocationInMW = 0;
+    // If non-zero can be used for power savings by throttling location when device hasn't moved.
+    private volatile float mSmallestDisplacementMeters = 0;
 
     /*
      * Getters and setters for properties needed to hold the options.
@@ -50,6 +52,14 @@
         return mPeriodInNS;
     }
 
+    public void setSmallestDisplacementMeters(float value) {
+        mSmallestDisplacementMeters = value;
+    }
+
+    public float getSmallestDisplacementMeters() {
+        return mSmallestDisplacementMeters;
+    }
+
     public void setSourceToUse(int source) {
         mSourcesToUse |= source;
     }
@@ -112,6 +122,7 @@
             options.setPeriodInNS(parcel.readLong());
             options.setSourceToUse(parcel.readInt());
             options.setFlag(parcel.readInt());
+            options.setSmallestDisplacementMeters(parcel.readFloat());
             return options;
         }
 
@@ -132,5 +143,6 @@
         parcel.writeLong(mPeriodInNS);
         parcel.writeInt(mSourcesToUse);
         parcel.writeInt(mFlags);
+        parcel.writeFloat(mSmallestDisplacementMeters);
     }
 }
diff --git a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
index fd3f402..29818ec 100644
--- a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
+++ b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
@@ -43,6 +43,14 @@
         return mOptions.getPeriodInNS();
     }
 
+    public void setSmallestDisplacementMeters(float value) {
+        mOptions.setSmallestDisplacementMeters(value);
+    }
+
+    public float getSmallestDisplacementMeters() {
+        return mOptions.getSmallestDisplacementMeters();
+    }
+
     public void setSourceToUse(int source) {
         mOptions.setSourceToUse(source);
     }
diff --git a/media/java/android/media/AudioFormat.java b/media/java/android/media/AudioFormat.java
index 9a0266d..3c973a2 100644
--- a/media/java/android/media/AudioFormat.java
+++ b/media/java/android/media/AudioFormat.java
@@ -38,6 +38,7 @@
     public static final int ENCODING_DEFAULT = 1;
 
     // These values must be kept in sync with core/jni/android_media_AudioFormat.h
+    // Also sync av/services/audiopolicy/managerdefault/ConfigParsingUtils.h
     /** Audio data format: PCM 16 bit per sample. Guaranteed to be supported by devices. */
     public static final int ENCODING_PCM_16BIT = 2;
     /** Audio data format: PCM 8 bit per sample. Not guaranteed to be supported by devices. */
@@ -48,6 +49,10 @@
     public static final int ENCODING_AC3 = 5;
     /** Audio data format: E-AC-3 compressed */
     public static final int ENCODING_E_AC3 = 6;
+    /** Audio data format: DTS compressed */
+    public static final int ENCODING_DTS = 7;
+    /** Audio data format: DTS HD compressed */
+    public static final int ENCODING_DTS_HD = 8;
 
     /** Invalid audio channel configuration */
     /** @deprecated use CHANNEL_INVALID instead  */
@@ -68,7 +73,7 @@
     public static final int CHANNEL_OUT_DEFAULT = 1;
 
     // Output channel mask definitions below are translated to the native values defined in
-    //  in /system/core/include/system/audio.h in the JNI code of AudioTrack
+    //  in /system/media/audio/include/system/audio.h in the JNI code of AudioTrack
     public static final int CHANNEL_OUT_FRONT_LEFT = 0x4;
     public static final int CHANNEL_OUT_FRONT_RIGHT = 0x8;
     public static final int CHANNEL_OUT_FRONT_CENTER = 0x10;
@@ -235,6 +240,8 @@
         case ENCODING_PCM_FLOAT:
         case ENCODING_AC3:
         case ENCODING_E_AC3:
+        case ENCODING_DTS:
+        case ENCODING_DTS_HD:
             return true;
         default:
             return false;
@@ -252,6 +259,8 @@
             return true;
         case ENCODING_AC3:
         case ENCODING_E_AC3:
+        case ENCODING_DTS:
+        case ENCODING_DTS_HD:
             return false;
         case ENCODING_INVALID:
         default:
@@ -400,6 +409,8 @@
          *     {@link AudioFormat#ENCODING_PCM_FLOAT},
          *     {@link AudioFormat#ENCODING_AC3},
          *     {@link AudioFormat#ENCODING_E_AC3}.
+         *     {@link AudioFormat#ENCODING_DTS},
+         *     {@link AudioFormat#ENCODING_DTS_HD}.
          * @return the same Builder instance.
          * @throws java.lang.IllegalArgumentException
          */
@@ -413,6 +424,8 @@
                 case ENCODING_PCM_FLOAT:
                 case ENCODING_AC3:
                 case ENCODING_E_AC3:
+                case ENCODING_DTS:
+                case ENCODING_DTS_HD:
                     mEncoding = encoding;
                     break;
                 case ENCODING_INVALID:
@@ -478,7 +491,9 @@
         ENCODING_PCM_16BIT,
         ENCODING_PCM_FLOAT,
         ENCODING_AC3,
-        ENCODING_E_AC3
+        ENCODING_E_AC3,
+        ENCODING_DTS,
+        ENCODING_DTS_HD
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Encoding {}
diff --git a/media/java/android/media/AudioPortEventHandler.java b/media/java/android/media/AudioPortEventHandler.java
index c05fd77..c49e8c2 100644
--- a/media/java/android/media/AudioPortEventHandler.java
+++ b/media/java/android/media/AudioPortEventHandler.java
@@ -40,6 +40,12 @@
     private static final int AUDIOPORT_EVENT_SERVICE_DIED = 3;
     private static final int AUDIOPORT_EVENT_NEW_LISTENER = 4;
 
+    /**
+     * Accessed by native methods: JNI Callback context.
+     */
+    @SuppressWarnings("unused")
+    private long mJniCallback;
+
     void init() {
         synchronized (this) {
             if (mHandler != null) {
@@ -63,9 +69,6 @@
                                 listeners = mListeners;
                             }
                         }
-                        if (listeners.isEmpty()) {
-                            return;
-                        }
                         // reset audio port cache if the event corresponds to a change coming
                         // from audio policy service or if mediaserver process died.
                         if (msg.what == AUDIOPORT_EVENT_PORT_LIST_UPDATED ||
@@ -73,6 +76,11 @@
                                 msg.what == AUDIOPORT_EVENT_SERVICE_DIED) {
                             AudioManager.resetAudioPortGeneration();
                         }
+
+                        if (listeners.isEmpty()) {
+                            return;
+                        }
+
                         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
                         ArrayList<AudioPatch> patches = new ArrayList<AudioPatch>();
                         if (msg.what != AUDIOPORT_EVENT_SERVICE_DIED) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 787320e..25e6594 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -123,7 +123,7 @@
     /** @deprecated */
     @Deprecated public static final int ROUTE_ALL               = 0xFFFFFFFF;
 
-    // Keep in sync with system/core/include/system/audio.h
+    // Keep in sync with system/media/audio/include/system/audio.h
     public static final int AUDIO_SESSION_ALLOCATE = 0;
 
     /*
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 93e2cbe..4c5fb40 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -21,7 +21,10 @@
 import java.lang.ref.WeakReference;
 import java.nio.ByteBuffer;
 import java.nio.NioUtils;
+
 import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -113,6 +116,14 @@
      */
     public static final int MODE_STREAM = 1;
 
+    /** @hide */
+    @IntDef({
+        MODE_STATIC,
+        MODE_STREAM
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TransferMode {}
+
     /**
      * State of an AudioTrack that was not successfully initialized upon creation.
      */
@@ -457,6 +468,179 @@
         }
     }
 
+    /**
+     * Builder class for {@link AudioTrack} objects.
+     * Use this class to configure and create an <code>AudioTrack</code> instance. By setting audio
+     * attributes and audio format parameters, you indicate which of those vary from the default
+     * behavior on the device.
+     * <p> Here is an example where <code>Builder</code> is used to specify all {@link AudioFormat}
+     * parameters, to be used by a new <code>AudioTrack</code> instance:
+     *
+     * <pre class="prettyprint">
+     * AudioTrack player = new AudioTrack.Builder()
+     *         .setAudioAttributes(new AudioAttributes.Builder()
+     *                  .setUsage(AudioAttributes.USAGE_ALARM)
+     *                  .setContentType(CONTENT_TYPE_MUSIC)
+     *                  .build())
+     *         .setAudioFormat(new AudioFormat.Builder()
+     *                 .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
+     *                 .setSampleRate(441000)
+     *                 .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+     *                 .build())
+     *         .setBufferSize(minBuffSize)
+     *         .build();
+     * </pre>
+     * <p>
+     * If the audio attributes are not set with {@link #setAudioAttributes(AudioAttributes)},
+     * attributes comprising {@link AudioAttributes#USAGE_MEDIA} will be used.
+     * <br>If the audio format is not specified or is incomplete, its sample rate will be the
+     * default output sample rate of the device (see
+     * {@link AudioManager#PROPERTY_OUTPUT_SAMPLE_RATE}), its channel configuration will be
+     * {@link AudioFormat#CHANNEL_OUT_STEREO} and the encoding will be
+     * {@link AudioFormat#ENCODING_PCM_16BIT}.
+     * <br>If the transfer mode is not specified with {@link #setTransferMode(int)},
+     * {@link AudioTrack#MODE_STREAM} will be used.
+     * <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will
+     * be generated.
+     */
+    public static class Builder {
+        private AudioAttributes mAttributes;
+        private AudioFormat mFormat;
+        private int mBufferSizeInBytes;
+        private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
+        private int mMode = MODE_STREAM;
+
+        /**
+         * Constructs a new Builder with the default values as described above.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the {@link AudioAttributes}.
+         * @param attributes a non-null {@link AudioAttributes} instance that describes the audio
+         *     data to be played.
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        public @NonNull Builder setAudioAttributes(@NonNull AudioAttributes attributes)
+                throws IllegalArgumentException {
+            if (attributes == null) {
+                throw new IllegalArgumentException("Illegal null AudioAttributes argument");
+            }
+            // keep reference, we only copy the data when building
+            mAttributes = attributes;
+            return this;
+        }
+
+        /**
+         * Sets the format of the audio data to be played by the {@link AudioTrack}.
+         * See {@link AudioFormat.Builder} for configuring the audio format parameters such
+         * as encoding, channel mask and sample rate.
+         * @param format a non-null {@link AudioFormat} instance.
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        public @NonNull Builder setAudioFormat(@NonNull AudioFormat format)
+                throws IllegalArgumentException {
+            if (format == null) {
+                throw new IllegalArgumentException("Illegal null AudioFormat argument");
+            }
+            // keep reference, we only copy the data when building
+            mFormat = format;
+            return this;
+        }
+
+        /**
+         * Sets the total size (in bytes) of the buffer where audio data is read from for playback.
+         * If using the {@link AudioTrack} in streaming mode
+         * (see {@link AudioTrack#MODE_STREAM}, you can write data into this buffer in smaller
+         * chunks than this size. See {@link #getMinBufferSize(int, int, int)} to determine
+         * the minimum required buffer size for the successful creation of an AudioTrack instance
+         * in streaming mode. Using values smaller than <code>getMinBufferSize()</code> will result
+         * in an exception when trying to build the <code>AudioTrack</code>.
+         * <br>If using the <code>AudioTrack</code> in static mode (see
+         * {@link AudioTrack#MODE_STATIC}), this is the maximum size of the sound that will be
+         * played by this instance.
+         * @param bufferSizeInBytes
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        public @NonNull Builder setBufferSizeInBytes(int bufferSizeInBytes)
+                throws IllegalArgumentException {
+            if (bufferSizeInBytes <= 0) {
+                throw new IllegalArgumentException("Invalid buffer size " + bufferSizeInBytes);
+            }
+            mBufferSizeInBytes = bufferSizeInBytes;
+            return this;
+        }
+
+        /**
+         * Sets the mode under which buffers of audio data are transferred from the
+         * {@link AudioTrack} to the framework.
+         * @param mode one of {@link AudioTrack#MODE_STREAM}, {@link AudioTrack#MODE_STATIC}.
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        public @NonNull Builder setTransferMode(@TransferMode int mode)
+                throws IllegalArgumentException {
+            switch(mode) {
+                case MODE_STREAM:
+                case MODE_STATIC:
+                    mMode = mode;
+                    break;
+                default:
+                    throw new IllegalArgumentException("Invalid transfer mode " + mode);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the session ID the {@link AudioTrack} will be attached to.
+         * @param sessionId a strictly positive ID number retrieved from another
+         *     <code>AudioTrack</code> via {@link AudioTrack#getAudioSessionId()} or allocated by
+         *     {@link AudioManager} via {@link AudioManager#generateAudioSessionId()}, or
+         *     {@link AudioManager#AUDIO_SESSION_ID_GENERATE}.
+         * @return the same Builder instance.
+         * @throws IllegalArgumentException
+         */
+        public @NonNull Builder setSessionId(int sessionId)
+                throws IllegalArgumentException {
+            if ((sessionId != AudioManager.AUDIO_SESSION_ID_GENERATE) && (sessionId < 1)) {
+                throw new IllegalArgumentException("Invalid audio session ID " + sessionId);
+            }
+            mSessionId = sessionId;
+            return this;
+        }
+
+        /**
+         * Builds an {@link AudioTrack} instance initialized with all the parameters set
+         * on this <code>Builder</code>.
+         * @return a new {@link AudioTrack} instance.
+         * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code>
+         *     were incompatible, or if they are not supported by the device.
+         */
+        public @NonNull AudioTrack build() throws UnsupportedOperationException {
+            if (mAttributes == null) {
+                mAttributes = new AudioAttributes.Builder()
+                        .setUsage(AudioAttributes.USAGE_MEDIA)
+                        .build();
+            }
+            if (mFormat == null) {
+                mFormat = new AudioFormat.Builder()
+                        .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+                        .setSampleRate(AudioSystem.getPrimaryOutputSamplingRate())
+                        .setEncoding(AudioFormat.ENCODING_DEFAULT)
+                        .build();
+            }
+            try {
+                return new AudioTrack(mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId);
+            } catch (IllegalArgumentException e) {
+                throw new UnsupportedOperationException(e.getMessage());
+            }
+        }
+    }
+
     // mask of all the channels supported by this implementation
     private static final int SUPPORTED_OUT_CHANNELS =
             AudioFormat.CHANNEL_OUT_FRONT_LEFT |
@@ -1315,7 +1499,9 @@
      * @param sizeInShorts the number of shorts to read in audioData after the offset.
      * @return the number of shorts that were written or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
+     *    the parameters don't resolve to valid data and indexes, or
+     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated.
      */
 
     public int write(short[] audioData, int offsetInShorts, int sizeInShorts) {
@@ -1375,7 +1561,9 @@
      *     queuing as much audio data for playback as possible without blocking.
      * @return the number of floats that were written, or {@link #ERROR_INVALID_OPERATION}
      *    if the object wasn't properly initialized, or {@link #ERROR_BAD_VALUE} if
-     *    the parameters don't resolve to valid data and indexes.
+     *    the parameters don't resolve to valid data and indexes, or
+     *    {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *    needs to be recreated.
      */
     public int write(float[] audioData, int offsetInFloats, int sizeInFloats,
             @WriteMode int writeMode) {
@@ -1436,7 +1624,9 @@
      *     <BR>With {@link #WRITE_NON_BLOCKING}, the write will return immediately after
      *     queuing as much audio data for playback as possible without blocking.
      * @return 0 or a positive number of bytes that were written, or
-     *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}
+     *     {@link #ERROR_BAD_VALUE}, {@link #ERROR_INVALID_OPERATION}, or
+     *     {@link AudioManager#ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *     needs to be recreated.
      */
     public int write(ByteBuffer audioData, int sizeInBytes,
             @WriteMode int writeMode) {
@@ -1749,5 +1939,4 @@
     private static void loge(String msg) {
         Log.e(TAG, msg);
     }
-
 }
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 9d07492..9ae468a 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -249,6 +249,22 @@
     Object getOwner() {
         return null;
     }
+
+    /**
+     * Get native context (buffer pointer) associated with this image.
+     * <p>
+     * This is a package private method that is only used internally. It can be
+     * used to get the native buffer pointer and passed to native, which may be
+     * passed to {@link ImageWriter#attachAndQueueInputImage} to avoid a reverse
+     * JNI call.
+     * </p>
+     *
+     * @return native context associated with this Image.
+     */
+    long getNativeContext() {
+        return 0;
+    }
+
     /**
      * <p>A single color plane of image data.</p>
      *
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index b2f7a20..3d8f9a0 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -98,7 +98,7 @@
      * @see Image
      */
     public static ImageReader newInstance(int width, int height, int format, int maxImages) {
-        if (format == PixelFormat.OPAQUE) {
+        if (format == ImageFormat.PRIVATE) {
             throw new IllegalArgumentException("To obtain an opaque ImageReader, please use"
                     + " newOpaqueInstance rather than newInstance");
         }
@@ -148,7 +148,7 @@
      * @see Image
      */
     public static ImageReader newOpaqueInstance(int width, int height, int maxImages) {
-        return new ImageReader(width, height, PixelFormat.OPAQUE, maxImages);
+        return new ImageReader(width, height, ImageFormat.PRIVATE, maxImages);
     }
 
     /**
@@ -261,7 +261,7 @@
      * @see ImageReader#newOpaqueInstance
      */
     public boolean isOpaque() {
-        return mFormat == PixelFormat.OPAQUE;
+        return mFormat == ImageFormat.PRIVATE;
     }
 
     /**
@@ -343,7 +343,7 @@
      * @hide
      */
     public Image acquireNextImageNoThrowISE() {
-        SurfaceImage si = new SurfaceImage();
+        SurfaceImage si = new SurfaceImage(mFormat);
         return acquireNextSurfaceImage(si) == ACQUIRE_SUCCESS ? si : null;
     }
 
@@ -408,7 +408,9 @@
      * @see #acquireLatestImage
      */
     public Image acquireNextImage() {
-        SurfaceImage si = new SurfaceImage();
+        // Initialize with reader format, but can be overwritten by native if the image
+        // format is different from the reader format.
+        SurfaceImage si = new SurfaceImage(mFormat);
         int status = acquireNextSurfaceImage(si);
 
         switch (status) {
@@ -565,9 +567,8 @@
        }
 
         SurfaceImage si = (SurfaceImage) image;
-        if (!si.isImageValid()) {
-            throw new IllegalStateException("Image is no longer valid");
-        }
+        si.throwISEIfImageIsInvalid();
+
         if (si.isAttachable()) {
             throw new IllegalStateException("Image was already detached from this ImageReader");
         }
@@ -607,7 +608,7 @@
             case ImageFormat.DEPTH16:
             case ImageFormat.DEPTH_POINT_CLOUD:
                 return 1;
-            case PixelFormat.OPAQUE:
+            case ImageFormat.PRIVATE:
                 return 0;
             default:
                 throw new UnsupportedOperationException(
@@ -684,18 +685,15 @@
     }
 
     private class SurfaceImage extends android.media.Image {
-        public SurfaceImage() {
+        public SurfaceImage(int format) {
             mIsImageValid = false;
+            mFormat = format;
         }
 
         @Override
         public void close() {
             if (mIsImageValid) {
-                if (!mIsDetached.get()) {
-                    // For detached images, the new owner is responsible for
-                    // releasing the resources
-                    ImageReader.this.releaseImage(this);
-                }
+                ImageReader.this.releaseImage(this);
             }
         }
 
@@ -705,70 +703,53 @@
 
         @Override
         public int getFormat() {
-            if (mIsImageValid) {
-                return ImageReader.this.mFormat;
-            } else {
-                throw new IllegalStateException("Image is already released");
-            }
+            throwISEIfImageIsInvalid();
+            return mFormat;
         }
 
         @Override
         public int getWidth() {
-            if (mIsImageValid) {
-                if (mWidth == -1) {
-                    mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() :
-                            nativeGetWidth();
-                }
-                return mWidth;
-            } else {
-                throw new IllegalStateException("Image is already released");
+            throwISEIfImageIsInvalid();
+            if (mWidth == -1) {
+                mWidth = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getWidth() :
+                        nativeGetWidth(mFormat);
             }
+            return mWidth;
         }
 
         @Override
         public int getHeight() {
-            if (mIsImageValid) {
-                if (mHeight == -1) {
-                    mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() :
-                            nativeGetHeight();
-                }
-                return mHeight;
-            } else {
-                throw new IllegalStateException("Image is already released");
+            throwISEIfImageIsInvalid();
+            if (mHeight == -1) {
+                mHeight = (getFormat() == ImageFormat.JPEG) ? ImageReader.this.getHeight() :
+                        nativeGetHeight(mFormat);
             }
+            return mHeight;
         }
 
         @Override
         public long getTimestamp() {
-            if (mIsImageValid) {
-                return mTimestamp;
-            } else {
-                throw new IllegalStateException("Image is already released");
-            }
+            throwISEIfImageIsInvalid();
+            return mTimestamp;
         }
 
         @Override
         public void setTimestamp(long timestampNs) {
-            if (mIsImageValid) {
-                mTimestamp = timestampNs;
-            } else {
-                throw new IllegalStateException("Image is already released");
-            }
+            throwISEIfImageIsInvalid();
+            mTimestamp = timestampNs;
         }
 
         @Override
         public Plane[] getPlanes() {
-            if (mIsImageValid) {
-                // Shallow copy is fine.
-                return mPlanes.clone();
-            } else {
-                throw new IllegalStateException("Image is already released");
-            }
+            throwISEIfImageIsInvalid();
+            // Shallow copy is fine.
+            return mPlanes.clone();
         }
 
         @Override
         public boolean isOpaque() {
-            return mFormat == PixelFormat.OPAQUE;
+            throwISEIfImageIsInvalid();
+            return mFormat == ImageFormat.PRIVATE;
         }
 
         @Override
@@ -782,15 +763,24 @@
 
         @Override
         boolean isAttachable() {
+            throwISEIfImageIsInvalid();
             return mIsDetached.get();
         }
 
         @Override
         ImageReader getOwner() {
+            throwISEIfImageIsInvalid();
             return ImageReader.this;
         }
 
+        @Override
+        long getNativeContext() {
+            throwISEIfImageIsInvalid();
+            return mNativeBuffer;
+        }
+
         private void setDetached(boolean detached) {
+            throwISEIfImageIsInvalid();
             mIsDetached.getAndSet(detached);
         }
 
@@ -798,8 +788,10 @@
             mIsImageValid = isValid;
         }
 
-        private boolean isImageValid() {
-            return mIsImageValid;
+        private void throwISEIfImageIsInvalid() {
+            if (!mIsImageValid) {
+                throw new IllegalStateException("Image is already closed");
+            }
         }
 
         private void clearSurfacePlanes() {
@@ -829,9 +821,7 @@
 
             @Override
             public ByteBuffer getBuffer() {
-                if (SurfaceImage.this.isImageValid() == false) {
-                    throw new IllegalStateException("Image is already released");
-                }
+                SurfaceImage.this.throwISEIfImageIsInvalid();
                 if (mBuffer != null) {
                     return mBuffer;
                 } else {
@@ -845,20 +835,14 @@
 
             @Override
             public int getPixelStride() {
-                if (SurfaceImage.this.isImageValid()) {
-                    return mPixelStride;
-                } else {
-                    throw new IllegalStateException("Image is already released");
-                }
+                SurfaceImage.this.throwISEIfImageIsInvalid();
+                return mPixelStride;
             }
 
             @Override
             public int getRowStride() {
-                if (SurfaceImage.this.isImageValid()) {
-                    return mRowStride;
-                } else {
-                    throw new IllegalStateException("Image is already released");
-                }
+                SurfaceImage.this.throwISEIfImageIsInvalid();
+                return mRowStride;
             }
 
             private void clearBuffer() {
@@ -885,7 +869,7 @@
          * This field is used to keep track of native object and used by native code only.
          * Don't modify.
          */
-        private long mLockedBuffer;
+        private long mNativeBuffer;
 
         /**
          * This field is set by native code during nativeImageSetup().
@@ -896,13 +880,14 @@
         private boolean mIsImageValid;
         private int mHeight = -1;
         private int mWidth = -1;
+        private int mFormat = ImageFormat.UNKNOWN;
         // If this image is detached from the ImageReader.
         private AtomicBoolean mIsDetached = new AtomicBoolean(false);
 
         private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat);
         private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
-        private synchronized native int nativeGetWidth();
-        private synchronized native int nativeGetHeight();
+        private synchronized native int nativeGetWidth(int format);
+        private synchronized native int nativeGetHeight(int format);
     }
 
     private synchronized native void nativeInit(Object weakSelf, int w, int h,
@@ -910,7 +895,7 @@
     private synchronized native void nativeClose();
     private synchronized native void nativeReleaseImage(Image i);
     private synchronized native Surface nativeGetSurface();
-    private synchronized native void nativeDetachImage(Image i);
+    private synchronized native int nativeDetachImage(Image i);
 
     /**
      * @return A return code {@code ACQUIRE_*}
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 20389a39..c18b463 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -16,7 +16,7 @@
 
 package android.media;
 
-import android.graphics.PixelFormat;
+import android.graphics.ImageFormat;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Looper;
@@ -77,9 +77,7 @@
     private int mWriterFormat;
 
     private final int mMaxImages;
-    // Keep track of the currently attached Image; or an attached Image that is
-    // released will be removed from this list.
-    private List<Image> mAttachedImages = new ArrayList<Image>();
+    // Keep track of the currently dequeued Image.
     private List<Image> mDequeuedImages = new ArrayList<Image>();
 
     /**
@@ -168,21 +166,38 @@
      * {@link Image#close()}.
      * </p>
      * <p>
-     * This call will block if all available input images have been filled by
+     * This call will block if all available input images have been queued by
      * the application and the downstream consumer has not yet consumed any.
-     * When an Image is consumed by the downstream consumer, an
+     * When an Image is consumed by the downstream consumer and released, an
      * {@link ImageListener#onInputImageReleased} callback will be fired, which
-     * indicates that there is one input Image available. It is recommended to
-     * dequeue next Image only after this callback is fired, in the steady state.
+     * indicates that there is one input Image available. For non-opaque formats
+     * (({@link ImageWriter#getFormat()} != {@link ImageFormat#PRIVATE})), it is
+     * recommended to dequeue the next Image only after this callback is fired,
+     * in the steady state.
+     * </p>
+     * <p>
+     * If the ImageWriter is opaque ({@link ImageWriter#getFormat()} ==
+     * {@link ImageFormat#PRIVATE}), the image buffer is inaccessible to
+     * the application, and calling this method will result in an
+     * {@link IllegalStateException}. Instead, the application should acquire
+     * opaque images from some other component (e.g. an opaque
+     * {@link ImageReader}), and queue them directly to this ImageWriter via the
+     * {@link ImageWriter#queueInputImage queueInputImage()} method.
      * </p>
      *
      * @return The next available input Image from this ImageWriter.
      * @throws IllegalStateException if {@code maxImages} Images are currently
-     *             dequeued.
+     *             dequeued, or the ImageWriter is opaque.
      * @see #queueInputImage
      * @see Image#close
      */
     public Image dequeueInputImage() {
+        if (mWriterFormat == ImageFormat.PRIVATE) {
+            throw new IllegalStateException(
+                    "Opaque ImageWriter doesn't support this operation since opaque images are"
+                            + " inaccessible to the application!");
+        }
+
         if (mDequeuedImages.size() >= mMaxImages) {
             throw new IllegalStateException("Already dequeued max number of Images " + mMaxImages);
         }
@@ -214,12 +229,19 @@
      * capture time.
      * </p>
      * <p>
-     * Passing in a non-opaque Image may result in a memory copy, which also
-     * requires a free input Image from this ImageWriter as the destination. In
-     * this case, this call will block, as {@link #dequeueInputImage} does, if
-     * there are no free Images available. To be safe, the application should ensure
-     * that there is at least one free Image available in this ImageWriter before calling
-     * this method.
+     * After this method is called and the downstream consumer consumes and
+     * releases the Image, an {@link ImageListener#onInputImageReleased
+     * onInputImageReleased()} callback will fire. The application can use this
+     * callback to avoid sending Images faster than the downstream consumer
+     * processing rate in steady state.
+     * </p>
+     * <p>
+     * Passing in an Image from some other component (e.g. an
+     * {@link ImageReader}) requires a free input Image from this ImageWriter as
+     * the destination. In this case, this call will block, as
+     * {@link #dequeueInputImage} does, if there are no free Images available.
+     * To avoid blocking, the application should ensure that there is at least
+     * one free Image available in this ImageWriter before calling this method.
      * </p>
      * <p>
      * After this call, the input Image is no longer valid for further access,
@@ -252,10 +274,17 @@
             ImageReader prevOwner = (ImageReader) image.getOwner();
             // Only do the image attach for opaque images for now. Do the image
             // copy for other formats. TODO: use attach for other formats to
-            // improve the performance, and fall back to copy when attach/detach fails.
+            // improve the performance, and fall back to copy when attach/detach
+            // fails. Right now, detach is guaranteed to fail as the buffer is
+            // locked when ImageReader#acquireNextImage is called. See bug 19962027.
             if (image.isOpaque()) {
                 prevOwner.detachImage(image);
-                attachInputImage(image);
+                attachAndQueueInputImage(image);
+                // This clears the native reference held by the original owner.
+                // When this Image is detached later by this ImageWriter, the
+                // native memory won't be leaked.
+                image.close();
+                return;
             } else {
                 Image inputImage = dequeueInputImage();
                 inputImage.setTimestamp(image.getTimestamp());
@@ -273,25 +302,35 @@
 
         /**
          * Only remove and cleanup the Images that are owned by this
-         * ImageWriter. Images detached from other owners are only
-         * temporarily owned by this ImageWriter and will be detached immediately
-         * after they are released by downstream consumers, so there is no need to
-         * keep track of them in mDequeuedImages.
+         * ImageWriter. Images detached from other owners are only temporarily
+         * owned by this ImageWriter and will be detached immediately after they
+         * are released by downstream consumers, so there is no need to keep
+         * track of them in mDequeuedImages.
          */
         if (ownedByMe) {
             mDequeuedImages.remove(image);
+            // Do not call close here, as close is essentially cancel image.
             WriterSurfaceImage wi = (WriterSurfaceImage) image;
             wi.clearSurfacePlanes();
             wi.setImageValid(false);
-        } else {
-            // This clears the native reference held by the original owner. When
-            // this Image is detached later by this ImageWriter, the native
-            // memory won't be leaked.
-            image.close();
         }
     }
 
     /**
+     * Get the ImageWriter format.
+     * <p>
+     * This format may be different than the Image format returned by
+     * {@link Image#getFormat()}. However, if the ImageWriter is opaque (format
+     * == {@link ImageFormat#PRIVATE}) , the images from it will also be opaque.
+     * </p>
+     *
+     * @return The ImageWriter format.
+     */
+    public int getFormat() {
+        return mWriterFormat;
+    }
+
+    /**
      * ImageWriter callback interface, used to to asynchronously notify the
      * application of various ImageWriter events.
      */
@@ -302,27 +341,33 @@
          * ImageWriter after the data consumption.
          * </p>
          * <p>
-         * The client can use this callback to indicate either an input Image is
-         * available to fill data into, or the input Image is returned and freed
-         * if it was attached from other components (e.g. an
-         * {@link ImageReader}). For the latter case, the ownership of the Image
-         * will be automatically removed by ImageWriter right before this
-         * callback is fired.
+         * The client can use this callback to be notified that an input Image
+         * has been consumed and released by the downstream consumer. More
+         * specifically, this callback will be fired for below cases:
+         * <li>The application dequeues an input Image via the
+         * {@link ImageWriter#dequeueInputImage dequeueInputImage()} method,
+         * uses it, and then queues it back to this ImageWriter via the
+         * {@link ImageWriter#queueInputImage queueInputImage()} method. After
+         * the downstream consumer uses and releases this image to this
+         * ImageWriter, this callback will be fired. This image will be
+         * available to be dequeued after this callback.</li>
+         * <li>The application obtains an Image from some other component (e.g.
+         * an {@link ImageReader}), uses it, and then queues it to this
+         * ImageWriter via {@link ImageWriter#queueInputImage queueInputImage()}.
+         * After the downstream consumer uses and releases this image to this
+         * ImageWriter, this callback will be fired.</li>
          * </p>
          *
          * @param writer the ImageWriter the callback is associated with.
          * @see ImageWriter
          * @see Image
          */
-        // TODO: the semantics is confusion, does't tell which buffer is
-        // released if an application is doing queueInputImage with a mix of
-        // buffers from dequeueInputImage and from an ImageReader. see b/19872821
         void onInputImageReleased(ImageWriter writer);
     }
 
     /**
-     * Register a listener to be invoked when an input Image is returned to
-     * the ImageWriter.
+     * Register a listener to be invoked when an input Image is returned to the
+     * ImageWriter.
      *
      * @param listener The listener that will be run.
      * @param handler The handler on which the listener should be invoked, or
@@ -383,38 +428,25 @@
     }
 
     /**
-     * Get the ImageWriter format.
      * <p>
-     * This format may be different than the Image format returned by
-     * {@link Image#getFormat()}
-     * </p>
-     *
-     * @return The ImageWriter format.
-     */
-    int getFormat() {
-        return mWriterFormat;
-    }
-
-
-    /**
-     * <p>
-     * Attach input Image to this ImageWriter.
+     * Attach and queue input Image to this ImageWriter.
      * </p>
      * <p>
-     * When an Image is from an opaque source (e.g. an opaque ImageReader created
-     * by {@link ImageReader#newOpaqueInstance}), or the source Image is so large
-     * that copying its data is too expensive, this method can be used to
-     * migrate the source Image into ImageWriter without a data copy. The source
-     * Image must be detached from its previous owner already, or this call will
-     * throw an {@link IllegalStateException}.
+     * When an Image is from an opaque source (e.g. an opaque ImageReader
+     * created by {@link ImageReader#newOpaqueInstance}), or the source Image is
+     * so large that copying its data is too expensive, this method can be used
+     * to migrate the source Image into ImageWriter without a data copy, and
+     * then queue it to this ImageWriter. The source Image must be detached from
+     * its previous owner already, or this call will throw an
+     * {@link IllegalStateException}.
      * </p>
      * <p>
-     * After this call, the ImageWriter takes ownership of this Image.
-     * This ownership will be automatically removed from this writer after the
+     * After this call, the ImageWriter takes ownership of this Image. This
+     * ownership will automatically be removed from this writer after the
      * consumer releases this Image, that is, after
-     * {@link ImageListener#onInputImageReleased}. The caller is
-     * responsible for closing this Image through {@link Image#close()} to free up
-     * the resources held by this Image.
+     * {@link ImageListener#onInputImageReleased}. The caller is responsible for
+     * closing this Image through {@link Image#close()} to free up the resources
+     * held by this Image.
      * </p>
      *
      * @param image The source Image to be attached and queued into this
@@ -423,7 +455,7 @@
      *             previous owner, or the Image is already attached to this
      *             ImageWriter, or the source Image is invalid.
      */
-    private void attachInputImage(Image image) {
+    private void attachAndQueueInputImage(Image image) {
         if (image == null) {
             throw new IllegalArgumentException("image shouldn't be null");
         }
@@ -441,15 +473,13 @@
             throw new IllegalStateException("Image was not detached from last owner, or image "
                     + " is not detachable");
         }
-        if (mAttachedImages.contains(image)) {
-            throw new IllegalStateException("Image was already attached to ImageWritter");
-        }
 
         // TODO: what if attach failed, throw RTE or detach a slot then attach?
         // need do some cleanup to make sure no orphaned
         // buffer caused leak.
-        nativeAttachImage(mNativeContext, image);
-        mAttachedImages.add(image);
+        Rect crop = image.getCropRect();
+        nativeAttachAndQueueImage(mNativeContext, image.getNativeContext(), image.getFormat(),
+                image.getTimestamp(), crop.left, crop.top, crop.right, crop.bottom);
     }
 
     /**
@@ -467,8 +497,6 @@
             synchronized (mListenerLock) {
                 listener = mListener;
             }
-            // TODO: detach Image from ImageWriter and remove the Image from
-            // mAttachedImage list.
             if (listener != null) {
                 listener.onInputImageReleased(ImageWriter.this);
             }
@@ -537,7 +565,7 @@
          * attached + queued successfully, and attach failed. Neither of the
          * cases need abort.
          */
-        cancelImage(mNativeContext,image);
+        cancelImage(mNativeContext, image);
         mDequeuedImages.remove(image);
         wi.clearSurfacePlanes();
         wi.setImageValid(false);
@@ -635,7 +663,7 @@
                 throw new IllegalStateException("Image is already released");
             }
 
-            return getFormat() == PixelFormat.OPAQUE;
+            return getFormat() == ImageFormat.PRIVATE;
         }
 
         @Override
@@ -668,6 +696,11 @@
         }
 
         @Override
+        long getNativeContext() {
+            return mNativeBuffer;
+        }
+
+        @Override
         public void close() {
             if (mIsImageValid.get()) {
                 getOwner().abortImage(this);
@@ -776,13 +809,15 @@
 
     private synchronized native void nativeClose(long nativeCtx);
 
-    private synchronized native void nativeAttachImage(long nativeCtx, Image image);
-
     private synchronized native void nativeDequeueInputImage(long nativeCtx, Image wi);
 
     private synchronized native void nativeQueueInputImage(long nativeCtx, Image image,
             long timestampNs, int left, int top, int right, int bottom);
 
+    private synchronized native int nativeAttachAndQueueImage(long nativeCtx,
+            long imageNativeBuffer, int imageFormat, long timestampNs, int left,
+            int top, int right, int bottom);
+
     private synchronized native void cancelImage(long nativeCtx, Image image);
 
     /**
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index a7f33fa..e028e3f 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -325,6 +325,13 @@
      */
     public static final int BUFFER_FLAG_END_OF_STREAM = 4;
 
+    /**
+     * This indicates that the codec is released because the media resources used by the codec
+     * have been reclaimed, for example by the resource manager.
+     * This is used by the {@link Callback#onCodecReleased} callback.
+     */
+    public static final int REASON_RECLAIMED = 1;
+
     private EventHandler mEventHandler;
     private Callback mCallback;
 
@@ -335,6 +342,7 @@
     private static final int CB_OUTPUT_AVAILABLE = 2;
     private static final int CB_ERROR = 3;
     private static final int CB_OUTPUT_FORMAT_CHANGE = 4;
+    private static final int CB_CODEC_RELEASED = 5;
 
     private class EventHandler extends Handler {
         private MediaCodec mCodec;
@@ -405,6 +413,13 @@
                     break;
                 }
 
+                case CB_CODEC_RELEASED:
+                {
+                    int reason = msg.arg2;
+                    mCallback.onCodecReleased(mCodec, reason);
+                    break;
+                }
+
                 default:
                 {
                     break;
@@ -540,6 +555,8 @@
      * or the flags are not set properly
      * (e.g. missing {@link #CONFIGURE_FLAG_ENCODE} for an encoder).
      * @throws IllegalStateException if not in the Initialized state.
+     * @throws CryptoException upon DRM error.
+     * @throws CodecException upon codec error.
      */
     public void configure(
             MediaFormat format,
@@ -718,6 +735,7 @@
         }
 
         /* Must be in sync with android_media_MediaCodec.cpp */
+        private final static int ACTION_FATAL = 0;
         private final static int ACTION_TRANSIENT = 1;
         private final static int ACTION_RECOVERABLE = 2;
 
@@ -1652,6 +1670,22 @@
          * @param format The new output format.
          */
         public abstract void onOutputFormatChanged(MediaCodec codec, MediaFormat format);
+
+        /**
+         * Called when the underlying codec component has been released.
+         * <p>
+         * At this point the MediaCodec must be released, as it has moved to terminal
+         * Uninitialized state.
+         *
+         * @param codec The MediaCodec object.
+         * @param reason The reason of the release.
+         */
+        public void onCodecReleased(MediaCodec codec, int reason) {
+            int errorCode = -1;
+            String detailMessage = "resources reclaimed";
+            onError(codec,
+                    new CodecException(errorCode, CodecException.ACTION_FATAL, detailMessage));
+        }
     }
 
     private void postEventFromNative(
diff --git a/media/java/android/media/MediaCrypto.java b/media/java/android/media/MediaCrypto.java
index c7c3fc2..da81b37 100644
--- a/media/java/android/media/MediaCrypto.java
+++ b/media/java/android/media/MediaCrypto.java
@@ -70,6 +70,20 @@
      */
     public final native boolean requiresSecureDecoderComponent(String mime);
 
+    /**
+     * Associate a MediaDrm session with this MediaCrypto instance.  The
+     * MediaDrm session is used to securely load decryption keys for a
+     * crypto scheme.  The crypto keys loaded through the MediaDrm session
+     * may be selected for use during the decryption operation performed
+     * by {@link android.media.MediaCodec#queueSecureInputBuffer} by specifying
+     * their key ids in the {@link android.media.MediaCodec.CryptoInfo#key} field.
+     * @param sessionId the MediaDrm sessionId to associate with this
+     * MediaCrypto instance
+     * @throws MediaCryptoException on failure to set the sessionId
+     */
+    public final native void setMediaDrmSession(byte[] sessionId)
+        throws MediaCryptoException;
+
     @Override
     protected void finalize() {
         native_finalize();
diff --git a/media/java/android/media/MediaCryptoException.java b/media/java/android/media/MediaCryptoException.java
index 44c5222..703e96f 100644
--- a/media/java/android/media/MediaCryptoException.java
+++ b/media/java/android/media/MediaCryptoException.java
@@ -17,8 +17,8 @@
 package android.media;
 
 /**
- * Exception thrown if MediaCrypto object could not be instantiated for
- * whatever reason.
+ * Exception thrown if MediaCrypto object could not be instantiated or
+ * if unable to perform an operation on the MediaCrypto object.
  */
 public final class MediaCryptoException extends Exception {
     public MediaCryptoException(String detailMessage) {
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 069f7ff..fc5fc43 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -17,9 +17,10 @@
 package android.media;
 
 import java.lang.ref.WeakReference;
-import java.util.UUID;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.UUID;
 import android.annotation.SystemApi;
 import android.os.Handler;
 import android.os.Looper;
@@ -98,12 +99,14 @@
  */
 public final class MediaDrm {
 
-    private final static String TAG = "MediaDrm";
+    private static final String TAG = "MediaDrm";
 
     private static final String PERMISSION = android.Manifest.permission.ACCESS_DRM_CERTIFICATES;
 
     private EventHandler mEventHandler;
     private OnEventListener mOnEventListener;
+    private OnKeysChangeListener mOnKeysChangeListener;
+    private OnExpirationUpdateListener mOnExpirationUpdateListener;
 
     private long mNativeContext;
 
@@ -227,6 +230,148 @@
     }
 
     /**
+     * Register a callback to be invoked when a session expiration update
+     * occurs.  The app's OnExpirationUpdateListener will be notified
+     * when the expiration time of the keys in the session have changed.
+     * @param listener the callback that will be run
+     * @param handler the handler on which the listener should be invoked, or
+     *     null if the listener should be invoked on the calling thread's looper.
+     */
+    public void setOnExpirationUpdateListener(OnExpirationUpdateListener listener,
+            Handler handler)
+    {
+        if (listener != null) {
+            Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+            if (looper != null) {
+                if (mEventHandler == null || mEventHandler.getLooper() != looper) {
+                    mEventHandler = new EventHandler(this, looper);
+                }
+            }
+        }
+        mOnExpirationUpdateListener = listener;
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when a drm session
+     * expiration update occurs
+     */
+    public interface OnExpirationUpdateListener
+    {
+        /**
+         * Called when a session expiration update occurs, to inform the app
+         * about the change in expiration time
+         *
+         * @param md the MediaDrm object on which the event occurred
+         * @param sessionId the DRM session ID on which the event occurred
+         * @param expirationTime the new expiration time for the keys in the session.
+         *     The time is in milliseconds, relative to the Unix epoch.
+         */
+        void onExpirationUpdate(MediaDrm md, byte[] sessionId, long expirationTime);
+    }
+
+    /**
+     * Register a callback to be invoked when the state of keys in a session
+     * change, e.g. when a license update occurs or when a license expires.
+     *
+     * @param listener the callback that will be run when key status changes
+     * @param handler the handler on which the listener should be invoked, or
+     *     null if the listener should be invoked on the calling thread's looper.
+     */
+    public void setOnKeysChangeListener(OnKeysChangeListener listener,
+            Handler handler)
+    {
+        if (listener != null) {
+            Looper looper = handler != null ? handler.getLooper() : Looper.myLooper();
+            if (looper != null) {
+                if (mEventHandler == null || mEventHandler.getLooper() != looper) {
+                    mEventHandler = new EventHandler(this, looper);
+                }
+            }
+        }
+        mOnKeysChangeListener = listener;
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when the keys in a drm
+     * session change states.
+     */
+    public interface OnKeysChangeListener
+    {
+        /**
+         * Called when the keys in a session change status, such as when the license
+         * is renewed or expires.
+         *
+         * @param md the MediaDrm object on which the event occurred
+         * @param sessionId the DRM session ID on which the event occurred
+         * @param keyInformation a list of {@link MediaDrm.KeyStatus}
+         *     instances indicating the status for each key in the session
+         * @param hasNewUsableKey indicates if a key has been added that is usable,
+         *     which may trigger an attempt to resume playback on the media stream
+         *     if it is currently blocked waiting for a key.
+         */
+        void onKeysChange(MediaDrm md, byte[] sessionId, List<KeyStatus> keyInformation,
+                boolean hasNewUsableKey);
+    }
+
+    /**
+     * The key is currently usable to decrypt media data
+     */
+    public static final int KEY_STATUS_USABLE = 0;
+
+    /**
+     * The key is no longer usable to decrypt media data because its
+     * expiration time has passed.
+     */
+    public static final int KEY_STATUS_EXPIRED = 1;
+
+    /**
+     * The key is not currently usable to decrypt media data because its
+     * output requirements cannot currently be met.
+     */
+    public static final int KEY_STATUS_OUTPUT_NOT_ALLOWED = 2;
+
+    /**
+     * The status of the key is not yet known and is being determined.
+     * The status will be updated with the actual status when it has
+     * been determined.
+     */
+    public static final int KEY_STATUS_PENDING = 3;
+
+    /**
+     * The key is not currently usable to decrypt media data because of an
+     * internal error in processing unrelated to input parameters.  This error
+     * is not actionable by an app.
+     */
+    public static final int KEY_STATUS_INTERNAL_ERROR = 4;
+
+
+    /**
+     * Defines the status of a key.
+     * A KeyStatus for each key in a session is provided to the
+     * {@link OnKeysChangeListener#onKeysChange}
+     * listener.
+     */
+    public static final class KeyStatus {
+        private final byte[] mKeyId;
+        private final int mStatusCode;
+
+        KeyStatus(byte[] keyId, int statusCode) {
+            mKeyId = keyId;
+            mStatusCode = statusCode;
+        }
+
+        /**
+         * Returns the status code for the key
+         */
+        public int getStatusCode() { return mStatusCode; }
+
+        /**
+         * Returns the id for the key
+         */
+        public byte[] getKeyId() { return mKeyId; }
+    }
+
+    /**
      * Register a callback to be invoked when an event occurs
      *
      * @param listener the callback that will be run
@@ -289,6 +434,8 @@
     public static final int EVENT_SESSION_RECLAIMED = 5;
 
     private static final int DRM_EVENT = 200;
+    private static final int EXPIRATION_UPDATE = 201;
+    private static final int KEYS_CHANGE = 202;
 
     private class EventHandler extends Handler
     {
@@ -308,8 +455,6 @@
             switch(msg.what) {
 
             case DRM_EVENT:
-                Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
-
                 if (mOnEventListener != null) {
                     if (msg.obj != null && msg.obj instanceof Parcel) {
                         Parcel parcel = (Parcel)msg.obj;
@@ -321,11 +466,46 @@
                         if (data.length == 0) {
                             data = null;
                         }
+
+                        Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
                         mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
                     }
                 }
                 return;
 
+            case KEYS_CHANGE:
+                if (mOnKeysChangeListener != null) {
+                    if (msg.obj != null && msg.obj instanceof Parcel) {
+                        Parcel parcel = (Parcel)msg.obj;
+                        byte[] sessionId = parcel.createByteArray();
+                        if (sessionId.length > 0) {
+                            List<KeyStatus> keyStatusList = keyStatusListFromParcel(parcel);
+                            boolean hasNewUsableKey = (parcel.readInt() != 0);
+
+                            Log.i(TAG, "Drm keys change");
+                            mOnKeysChangeListener.onKeysChange(mMediaDrm, sessionId, keyStatusList,
+                                    hasNewUsableKey);
+                        }
+                    }
+                }
+                return;
+
+            case EXPIRATION_UPDATE:
+                if (mOnExpirationUpdateListener != null) {
+                    if (msg.obj != null && msg.obj instanceof Parcel) {
+                        Parcel parcel = (Parcel)msg.obj;
+                        byte[] sessionId = parcel.createByteArray();
+                        if (sessionId.length > 0) {
+                            long expirationTime = parcel.readLong();
+
+                            Log.i(TAG, "Drm key expiration update: " + expirationTime);
+                            mOnExpirationUpdateListener.onExpirationUpdate(mMediaDrm, sessionId,
+                                    expirationTime);
+                        }
+                    }
+                }
+                return;
+
             default:
                 Log.e(TAG, "Unknown message type " + msg.what);
                 return;
@@ -333,7 +513,21 @@
         }
     }
 
-    /*
+    /**
+     * Parse a list of KeyStatus objects from an event parcel
+     */
+    private List<KeyStatus> keyStatusListFromParcel(Parcel parcel) {
+        int nelems = parcel.readInt();
+        List<KeyStatus> keyStatusList = new ArrayList(nelems);
+        while (nelems-- > 0) {
+            byte[] keyId = parcel.createByteArray();
+            int keyStatusCode = parcel.readInt();
+            keyStatusList.add(new KeyStatus(keyId, keyStatusCode));
+        }
+        return keyStatusList;
+    }
+
+    /**
      * This method is called from native code when an event occurs.  This method
      * just uses the EventHandler system to post the event back to the main app thread.
      * We use a weak reference to the original MediaPlayer object so that the native
@@ -341,14 +535,14 @@
      * the cookie passed to native_setup().)
      */
     private static void postEventFromNative(Object mediadrm_ref,
-            int eventType, int extra, Object obj)
+            int what, int eventType, int extra, Object obj)
     {
-        MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
+        MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get();
         if (md == null) {
             return;
         }
         if (md.mEventHandler != null) {
-            Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
+            Message m = md.mEventHandler.obtainMessage(what, eventType, extra, obj);
             md.mEventHandler.sendMessage(m);
         }
     }
@@ -404,7 +598,7 @@
     /**
      * Contains the opaque data an app uses to request keys from a license server
      */
-    public final static class KeyRequest {
+    public static final class KeyRequest {
         private byte[] mData;
         private String mDefaultUrl;
         private int mRequestType;
@@ -521,7 +715,7 @@
      * Contains the opaque data an app uses to request a certificate from a provisioning
      * server
      */
-    public final static class ProvisionRequest {
+    public static final class ProvisionRequest {
         ProvisionRequest() {}
 
         /**
@@ -812,7 +1006,7 @@
      *
      * @hide - not part of the public API at this time
      */
-    public final static class CertificateRequest {
+    public static final class CertificateRequest {
         private byte[] mData;
         private String mDefaultUrl;
 
@@ -860,7 +1054,7 @@
      *
      * @hide - not part of the public API at this time
      */
-    public final static class Certificate {
+    public static final class Certificate {
         Certificate() {}
 
         /**
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 0c1c7e9..726622f 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -439,6 +439,22 @@
     public static final String KEY_PRIORITY = "priority";
 
     /**
+     * A key describing the desired operating frame rate for video or sample rate for audio
+     * that the codec will need to operate at.
+     * <p>
+     * The associated value is an integer or a float representing frames-per-second or
+     * samples-per-second
+     * <p>
+     * This is used for cases like high-speed/slow-motion video capture, where the video encoder
+     * format contains the target playback rate (e.g. 30fps), but the component must be able to
+     * handle the high operating capture rate (e.g. 240fps).
+     * <p>
+     * This rate will be used by codec for resource planning and setting the operating points.
+     *
+     */
+    public static final String KEY_OPERATING_RATE = "operating-rate";
+
+    /**
      * A key describing the desired profile to be used by an encoder.
      * Constants are declared in {@link MediaCodecInfo.CodecProfileLevel}.
      * This key is only supported for codecs that specify a profile.
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 9a69c06..9aa8003 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -498,5 +498,11 @@
      * The video rotation angle may be 0, 90, 180, or 270 degrees.
      */
     public static final int METADATA_KEY_VIDEO_ROTATION = 24;
+    /**
+     * This key retrieves the original capture framerate, if it's
+     * available. The capture framerate will be a floating point
+     * number.
+     */
+    public static final int METADATA_KEY_CAPTURE_FRAMERATE = 25;
     // Add more here...
 }
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 058cfd2..876aebc 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -171,7 +171,7 @@
         public final static int AUDIO_SOURCE_INVALID = -1;
 
       /* Do not change these values without updating their counterparts
-       * in system/core/include/system/audio.h!
+       * in system/media/audio/include/system/audio.h!
        */
 
         /** Default audio source **/
diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java
new file mode 100644
index 0000000..7350bd4
--- /dev/null
+++ b/media/java/android/media/MediaSync.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.media.AudioTrack;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.view.Surface;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * MediaSync class can be used to synchronously playback audio and video streams.
+ * It can be used to play audio-only or video-only stream, too.
+ *
+ * <p>MediaSync is generally used like this:
+ * <pre>
+ * MediaSync sync = new MediaSync();
+ * sync.configureSurface(surface);
+ * Surface inputSurface = sync.createInputSurface();
+ * ...
+ * // MediaCodec videoDecoder = ...;
+ * videoDecoder.configure(format, inputSurface, ...);
+ * ...
+ * sync.configureAudioTrack(audioTrack, nativeSampleRateInHz);
+ * sync.setCallback(new MediaSync.Callback() {
+ *     \@Override
+ *     public void onReturnAudioBuffer(MediaSync sync, ByteBuffer audioBuffer, int bufferIndex) {
+ *         ...
+ *     }
+ * });
+ * // This needs to be done since sync is paused on creation.
+ * sync.setPlaybackRate(1.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
+ *
+ * for (;;) {
+ *   ...
+ *   // send video frames to surface for rendering, e.g., call
+ *   // videoDecoder.releaseOutputBuffer(videoOutputBufferIx, videoPresentationTimeNs);
+ *   // More details are available as below.
+ *   ...
+ *   sync.queueAudio(audioByteBuffer, bufferIndex, size, audioPresentationTimeUs); // non-blocking.
+ *   // The audioByteBuffer and bufferIndex will be returned via callback.
+ *   // More details are available as below.
+ *   ...
+ *     ...
+ * }
+ * sync.setPlaybackRate(0.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
+ * sync.release();
+ * sync = null;
+ *
+ * // The following code snippet illustrates how video/audio raw frames are created by
+ * // MediaCodec's, how they are fed to MediaSync and how they are returned by MediaSync.
+ * // This is the callback from MediaCodec.
+ * onOutputBufferAvailable(MediaCodec codec, int bufferIndex, BufferInfo info) {
+ *     // ...
+ *     if (codec == videoDecoder) {
+ *         // surface timestamp must contain media presentation time in nanoseconds.
+ *         codec.releaseOutputBuffer(bufferIndex, 1000 * info.presentationTime);
+ *     } else {
+ *         ByteBuffer audioByteBuffer = codec.getOutputBuffer(bufferIndex);
+ *         sync.queueByteBuffer(audioByteBuffer, bufferIndex, info.size, info.presentationTime);
+ *     }
+ *     // ...
+ * }
+ *
+ * // This is the callback from MediaSync.
+ * onReturnAudioBuffer(MediaSync sync, ByteBuffer buffer, int bufferIndex) {
+ *     // ...
+ *     audioDecoder.releaseBuffer(bufferIndex, false);
+ *     // ...
+ * }
+ *
+ * </pre>
+ *
+ * The client needs to configure corresponding sink (i.e., Surface and AudioTrack) based on
+ * the stream type it will play.
+ * <p>
+ * For video, the client needs to call {@link #createInputSurface} to obtain a surface on
+ * which it will render video frames.
+ * <p>
+ * For audio, the client needs to set up audio track correctly, e.g., using {@link
+ * AudioTrack#MODE_STREAM}. The audio buffers are sent to MediaSync directly via {@link
+ * #queueAudio}, and are returned to the client via {@link Callback#onReturnAudioBuffer}
+ * asynchronously. The client should not modify an audio buffer till it's returned.
+ * <p>
+ * The client can optionally pre-fill audio/video buffers by setting playback rate to 0.0,
+ * and then feed audio/video buffers to corresponding components. This can reduce possible
+ * initial underrun.
+ * <p>
+ */
+final public class MediaSync {
+    /**
+     * MediaSync callback interface. Used to notify the user asynchronously
+     * of various MediaSync events.
+     */
+    public static abstract class Callback {
+        /**
+         * Called when returning an audio buffer which has been consumed.
+         *
+         * @param sync The MediaSync object.
+         * @param audioBuffer The returned audio buffer.
+         */
+        public abstract void onReturnAudioBuffer(
+                MediaSync sync, ByteBuffer audioBuffer, int bufferIndex);
+    }
+
+    private static final String TAG = "MediaSync";
+
+    private static final int EVENT_CALLBACK = 1;
+    private static final int EVENT_SET_CALLBACK = 2;
+
+    private static final int CB_RETURN_AUDIO_BUFFER = 1;
+
+    private static class AudioBuffer {
+        public ByteBuffer mByteBuffer;
+        public int mBufferIndex;
+        public int mSizeInBytes;
+        long mPresentationTimeUs;
+
+        public AudioBuffer(ByteBuffer byteBuffer, int bufferIndex,
+                           int sizeInBytes, long presentationTimeUs) {
+            mByteBuffer = byteBuffer;
+            mBufferIndex = bufferIndex;
+            mSizeInBytes = sizeInBytes;
+            mPresentationTimeUs = presentationTimeUs;
+        }
+    }
+
+    private final Object mCallbackLock = new Object();
+    private Handler mCallbackHandler = null;
+    private MediaSync.Callback mCallback = null;
+
+    private int mNativeSampleRateInHz = 0;
+
+    private Thread mAudioThread = null;
+    // Created on mAudioThread when mAudioThread is started. When used on user thread, they should
+    // be guarded by checking mAudioThread.
+    private Handler mAudioHandler = null;
+    private Looper mAudioLooper = null;
+
+    private final Object mAudioLock = new Object();
+    private AudioTrack mAudioTrack = null;
+    private List<AudioBuffer> mAudioBuffers = new LinkedList<AudioBuffer>();
+    private float mPlaybackRate = 0.0f;
+
+    private long mNativeContext;
+
+    /**
+     * Class constructor. On creation, MediaSync is paused, i.e., playback rate is 0.0f.
+     */
+    public MediaSync() {
+        native_setup();
+    }
+
+    private native final void native_setup();
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    private native final void native_finalize();
+
+    /**
+     * Make sure you call this when you're done to free up any opened
+     * component instance instead of relying on the garbage collector
+     * to do this for you at some point in the future.
+     */
+    public final void release() {
+        returnAudioBuffers();
+        if (mAudioThread != null) {
+            if (mAudioLooper != null) {
+                mAudioLooper.quit();
+            }
+        }
+        setCallback(null, null);
+        native_release();
+    }
+
+    private native final void native_release();
+
+    /**
+     * Sets an asynchronous callback for actionable MediaSync events.
+     * It shouldn't be called inside callback.
+     *
+     * @param cb The callback that will run.
+     * @param handler The Handler that will run the callback. Using null means to use MediaSync's
+     *     internal handler if it exists.
+     */
+    public void setCallback(/* MediaSync. */ Callback cb, Handler handler) {
+        synchronized(mCallbackLock) {
+            if (handler != null) {
+                mCallbackHandler = handler;
+            } else {
+                Looper looper;
+                if ((looper = Looper.myLooper()) == null) {
+                    looper = Looper.getMainLooper();
+                }
+                if (looper == null) {
+                    mCallbackHandler = null;
+                } else {
+                    mCallbackHandler = new Handler(looper);
+                }
+            }
+
+            mCallback = cb;
+        }
+    }
+
+    /**
+     * Configures the output surface for MediaSync.
+     *
+     * @param surface Specify a surface on which to render the video data.
+     * @throws IllegalArgumentException if the surface has been released, or is invalid.
+     *     or can not be connected.
+     * @throws IllegalStateException if not in the Initialized state, or another surface
+     *     has already been configured.
+     */
+    public void configureSurface(Surface surface) {
+        native_configureSurface(surface);
+    }
+
+    private native final void native_configureSurface(Surface surface);
+
+    /**
+     * Configures the audio track for MediaSync.
+     *
+     * @param audioTrack Specify an AudioTrack through which to render the audio data.
+     * @throws IllegalArgumentException if the audioTrack has been released, or is invalid,
+     *     or nativeSampleRateInHz is invalid.
+     * @throws IllegalStateException if not in the Initialized state, or another audio track
+     *     has already been configured.
+     */
+    public void configureAudioTrack(AudioTrack audioTrack, int nativeSampleRateInHz) {
+        if (audioTrack != null && nativeSampleRateInHz <= 0) {
+            final String msg = "Native sample rate " + nativeSampleRateInHz + " is invalid";
+            throw new IllegalArgumentException(msg);
+        }
+        native_configureAudioTrack(audioTrack, nativeSampleRateInHz);
+        mAudioTrack = audioTrack;
+        mNativeSampleRateInHz = nativeSampleRateInHz;
+        if (mAudioThread == null) {
+            createAudioThread();
+        }
+    }
+
+    private native final void native_configureAudioTrack(
+            AudioTrack audioTrack, int nativeSampleRateInHz);
+
+    /**
+     * Requests a Surface to use as the input. This may only be called after
+     * {@link #configureSurface}.
+     * <p>
+     * The application is responsible for calling release() on the Surface when
+     * done.
+     * @throws IllegalStateException if not configured, or another input surface has
+     *     already been created.
+     */
+    public native final Surface createInputSurface();
+
+    /**
+     * Specifies resampling as audio mode for variable rate playback, i.e.,
+     * resample the waveform based on the requested playback rate to get
+     * a new waveform, and play back the new waveform at the original sampling
+     * frequency.
+     * When rate is larger than 1.0, pitch becomes higher.
+     * When rate is smaller than 1.0, pitch becomes lower.
+     */
+    public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0;
+
+    /**
+     * Specifies time stretching as audio mode for variable rate playback.
+     * Time stretching changes the duration of the audio samples without
+     * affecting its pitch.
+     * FIXME: implement time strectching.
+     * @hide
+     */
+    public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1;
+
+    /** @hide */
+    @IntDef(
+        value = {
+            PLAYBACK_RATE_AUDIO_MODE_RESAMPLE,
+            PLAYBACK_RATE_AUDIO_MODE_STRETCH })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PlaybackRateAudioMode {}
+
+    /**
+     * Sets playback rate. It does same as {@link #setPlaybackRate(float, int)},
+     * except that it always uses {@link #PLAYBACK_RATE_AUDIO_MODE_STRETCH} for audioMode.
+     *
+     * @param rate the ratio between desired playback rate and normal one. 1.0 means normal
+     *     playback speed. 0.0 means stop or pause. Value larger than 1.0 means faster playback,
+     *     while value between 0.0 and 1.0 for slower playback.
+     *
+     * @throws IllegalStateException if the internal sync engine or the audio track has not
+     *     been initialized.
+     * TODO: unhide when PLAYBACK_RATE_AUDIO_MODE_STRETCH is supported.
+     * @hide
+     */
+    public void setPlaybackRate(float rate) {
+        setPlaybackRate(rate, PLAYBACK_RATE_AUDIO_MODE_STRETCH);
+    }
+
+    /**
+     * Sets playback rate and audio mode.
+     *
+     * <p> The supported audio modes are:
+     * <ul>
+     * <li> {@link #PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
+     * </ul>
+     *
+     * @param rate the ratio between desired playback rate and normal one. 1.0 means normal
+     *     playback speed. 0.0 means stop or pause. Value larger than 1.0 means faster playback,
+     *     while value between 0.0 and 1.0 for slower playback.
+     * @param audioMode audio playback mode. Must be one of the supported
+     *     audio modes.
+     *
+     * @throws IllegalStateException if the internal sync engine or the audio track has not
+     *     been initialized.
+     * @throws IllegalArgumentException if audioMode is not supported.
+     */
+    public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) {
+        if (!isAudioPlaybackModeSupported(audioMode)) {
+            final String msg = "Audio playback mode " + audioMode + " is not supported";
+            throw new IllegalArgumentException(msg);
+        }
+
+        int status = AudioTrack.SUCCESS;
+        if (mAudioTrack != null) {
+            int playbackSampleRate = (int)(rate * mNativeSampleRateInHz + 0.5);
+            rate = playbackSampleRate / (float)mNativeSampleRateInHz;
+
+            try {
+                if (rate == 0.0) {
+                    mAudioTrack.pause();
+                } else {
+                    status = mAudioTrack.setPlaybackRate(playbackSampleRate);
+                    mAudioTrack.play();
+                }
+            } catch (IllegalStateException e) {
+                throw e;
+            }
+        }
+
+        if (status != AudioTrack.SUCCESS) {
+            throw new IllegalArgumentException("Fail to set playback rate in audio track");
+        }
+
+        synchronized(mAudioLock) {
+            mPlaybackRate = rate;
+        }
+        if (mPlaybackRate != 0.0 && mAudioThread != null) {
+            postRenderAudio(0);
+        }
+        native_setPlaybackRate(mPlaybackRate);
+    }
+
+    private native final void native_setPlaybackRate(float rate);
+
+    /*
+     * Test whether a given audio playback mode is supported.
+     * TODO query supported AudioPlaybackMode from audio track.
+     */
+    private boolean isAudioPlaybackModeSupported(int mode) {
+        return (mode == PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
+    }
+
+   /**
+    * Get current playback position.
+    * <p>
+    * The MediaTimestamp represents a clock ticking during media playback. It's represented
+    * by an anchor frame ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime})
+    * and clock speed ({@link MediaTimestamp#clockRate}). For continous playback with
+    * constant speed, its anchor frame doesn't change that often. Thereafter, it's recommended
+    * to not call this method often.
+    * <p>
+    * To help users to get current playback position, this method always returns the timestamp of
+    * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They
+    * can be used as current playback position.
+    *
+    * @param timestamp a reference to a non-null MediaTimestamp instance allocated
+    *         and owned by caller.
+    * @return true if a timestamp is available, or false if no timestamp is available.
+    *         If a timestamp if available, the MediaTimestamp instance is filled in with
+    *         playback rate, together with the current media timestamp and the system nanoTime
+    *         corresponding to the measured media timestamp.
+    *         In the case that no timestamp is available, any supplied instance is left unaltered.
+    */
+    public boolean getTimestamp(@NonNull MediaTimestamp timestamp)
+    {
+        if (timestamp == null) {
+            throw new IllegalArgumentException();
+        }
+        return native_getTimestamp(timestamp);
+    }
+
+    private native final boolean native_getTimestamp(MediaTimestamp timestamp);
+
+    /**
+     * Queues the audio data asynchronously for playback (AudioTrack must be in streaming mode).
+     * @param audioData the buffer that holds the data to play. This buffer will be returned
+     *     to the client via registered callback.
+     * @param bufferIndex the buffer index used to identify audioData. It will be returned to
+     *     the client along with audioData. This helps applications to keep track of audioData.
+     * @param sizeInBytes number of bytes to queue.
+     * @param presentationTimeUs the presentation timestamp in microseconds for the first frame
+     *     in the buffer.
+     * @throws IllegalStateException if audio track is not configured or internal configureation
+     *     has not been done correctly.
+     */
+    public void queueAudio(
+            ByteBuffer audioData, int bufferIndex, int sizeInBytes, long presentationTimeUs) {
+        if (mAudioTrack == null || mAudioThread == null) {
+            throw new IllegalStateException(
+                    "AudioTrack is NOT configured or audio thread is not created");
+        }
+
+        synchronized(mAudioLock) {
+            mAudioBuffers.add(new AudioBuffer(
+                    audioData, bufferIndex, sizeInBytes, presentationTimeUs));
+        }
+
+        if (mPlaybackRate != 0.0) {
+            postRenderAudio(0);
+        }
+    }
+
+    // When called on user thread, make sure to check mAudioThread != null.
+    private void postRenderAudio(long delayMillis) {
+        mAudioHandler.postDelayed(new Runnable() {
+            public void run() {
+                synchronized(mAudioLock) {
+                    if (mPlaybackRate == 0.0) {
+                        return;
+                    }
+
+                    if (mAudioBuffers.isEmpty()) {
+                        return;
+                    }
+
+                    AudioBuffer audioBuffer = mAudioBuffers.get(0);
+                    int sizeWritten = mAudioTrack.write(
+                            audioBuffer.mByteBuffer,
+                            audioBuffer.mSizeInBytes,
+                            AudioTrack.WRITE_NON_BLOCKING);
+                    if (sizeWritten > 0) {
+                        if (audioBuffer.mPresentationTimeUs != -1) {
+                            native_updateQueuedAudioData(
+                                    audioBuffer.mSizeInBytes, audioBuffer.mPresentationTimeUs);
+                            audioBuffer.mPresentationTimeUs = -1;
+                        }
+
+                        if (sizeWritten == audioBuffer.mSizeInBytes) {
+                            postReturnByteBuffer(audioBuffer);
+                            mAudioBuffers.remove(0);
+                            if (!mAudioBuffers.isEmpty()) {
+                                postRenderAudio(0);
+                            }
+                            return;
+                        }
+
+                        audioBuffer.mSizeInBytes -= sizeWritten;
+                    }
+                    // TODO: wait time depends on fullness of audio track.
+                    postRenderAudio(10);
+                }
+            }
+        }, delayMillis);
+    }
+
+    private native final void native_updateQueuedAudioData(
+            int sizeInBytes, long presentationTimeUs);
+
+    private final void postReturnByteBuffer(final AudioBuffer audioBuffer) {
+        synchronized(mCallbackLock) {
+            if (mCallbackHandler != null) {
+                final MediaSync sync = this;
+                mCallbackHandler.post(new Runnable() {
+                    public void run() {
+                        synchronized(mCallbackLock) {
+                            if (mCallbackHandler == null
+                                    || mCallbackHandler.getLooper().getThread()
+                                            != Thread.currentThread()) {
+                                // callback handler has been changed.
+                                return;
+                            }
+                            if (mCallback != null) {
+                                mCallback.onReturnAudioBuffer(sync, audioBuffer.mByteBuffer,
+                                        audioBuffer.mBufferIndex);
+                            }
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    private final void returnAudioBuffers() {
+        synchronized(mAudioLock) {
+            for (AudioBuffer audioBuffer: mAudioBuffers) {
+                postReturnByteBuffer(audioBuffer);
+            }
+            mAudioBuffers.clear();
+        }
+    }
+
+    private void createAudioThread() {
+        mAudioThread = new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                synchronized(mAudioLock) {
+                    mAudioLooper = Looper.myLooper();
+                    mAudioHandler = new Handler();
+                    mAudioLock.notify();
+                }
+                Looper.loop();
+            }
+        };
+        mAudioThread.start();
+
+        synchronized(mAudioLock) {
+            try {
+                mAudioLock.wait();
+            } catch(InterruptedException e) {
+            }
+        }
+    }
+
+    static {
+        System.loadLibrary("media_jni");
+        native_init();
+    }
+
+    private static native final void native_init();
+}
diff --git a/media/java/android/media/MediaTimestamp.java b/media/java/android/media/MediaTimestamp.java
new file mode 100644
index 0000000..4b7e827
--- /dev/null
+++ b/media/java/android/media/MediaTimestamp.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Structure that groups clock rate of the stream playback, together with the media timestamp
+ * of an anchor frame and the system time when that frame was presented or is committed
+ * to be presented.
+ * The "present" means that audio/video produced on device is detectable by an external
+ * observer off device.
+ * The time is based on the implementation's best effort, using whatever knowledge
+ * is available to the system, but cannot account for any delay unknown to the implementation.
+ * The anchor frame could be any frame, including just-rendered frame, dependent on how
+ * it's selected. When the anchor frame is the just-rendered one, the media time stands for
+ * current position of the playback.
+ *
+ * @see MediaSync#getTimestamp
+ */
+public final class MediaTimestamp
+{
+    /**
+     * Media timestamp in microseconds.
+     */
+    public long mediaTimeUs;
+
+    /**
+     * The {@link java.lang.System#nanoTime} corresponding to the media timestamp.
+     */
+    public long nanoTime;
+
+    /**
+     * Media clock rate.
+     * It is 1.0 if media clock is in sync with the system clock;
+     * greater than 1.0 if media clock is faster than the system clock;
+     * less than 1.0 if media clock is slower than the system clock.
+     */
+    public float clockRate;
+}
diff --git a/media/java/android/media/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
index 642078a..96d12fd 100644
--- a/media/java/android/media/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -16,6 +16,7 @@
 
 package android.media.midi;
 
+import android.media.midi.MidiDeviceInfo;
 import android.os.ParcelFileDescriptor;
 
 /** @hide */
@@ -27,4 +28,6 @@
 
     // connects the input port pfd to the specified output port
     void connectPorts(IBinder token, in ParcelFileDescriptor pfd, int outputPortNumber);
+
+    MidiDeviceInfo getDeviceInfo();
 }
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index 569f7c6..6b36554 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -34,9 +34,6 @@
 /**
  * This class is used for sending and receiving data to and from a MIDI device
  * Instances of this class are created by {@link MidiManager#openDevice}.
- *
- * CANDIDATE FOR PUBLIC API
- * @hide
  */
 public final class MidiDevice implements Closeable {
     private static final String TAG = "MidiDevice";
@@ -49,6 +46,11 @@
 
     private final CloseGuard mGuard = CloseGuard.get();
 
+    /**
+     * This class represents a connection between the output port of one device
+     * and the input port of another. Created by {@link #connectPorts}.
+     * Close this object to terminate the connection.
+     */
     public class MidiConnection implements Closeable {
         private final IBinder mToken;
         private final MidiInputPort mInputPort;
@@ -134,11 +136,11 @@
     /**
      * Connects the supplied {@link MidiInputPort} to the output port of this device
      * with the specified port number. Once the connection is made, the MidiInput port instance
-     * can no longer receive data via its {@link MidiReciever.receive} method.
-     * This method returns a {@link #MidiConnection} object, which can be used to close the connection
+     * can no longer receive data via its {@link MidiReceiver#onReceive} method.
+     * This method returns a {@link MidiDevice.MidiConnection} object, which can be used to close the connection
      * @param inputPort the inputPort to connect
      * @param outputPortNumber the port number of the output port to connect inputPort to.
-     * @return {@link #MidiConnection} object if the connection is successful, or null in case of failure
+     * @return {@link MidiDevice.MidiConnection} object if the connection is successful, or null in case of failure
      */
     public MidiConnection connectPorts(MidiInputPort inputPort, int outputPortNumber) {
         if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
index 7201e25..af108eb 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -237,29 +237,23 @@
     }
 
     /**
-     * Returns information about an input port.
+     * Returns information about the device's ports.
+     * The ports are in unspecified order.
      *
-     * @param portNumber the number of the input port
-     * @return the input port's information object
+     * @return array of {@link PortInfo}
      */
-    public PortInfo getInputPortInfo(int portNumber) {
-        if (portNumber < 0 || portNumber >= mInputPortCount) {
-            throw new IllegalArgumentException("portNumber out of range");
-        }
-        return new PortInfo(PortInfo.TYPE_INPUT, portNumber, mInputPortNames[portNumber]);
-    }
+    public PortInfo[] getPortList() {
+        PortInfo[] portInfoList = new PortInfo[mInputPortCount + mOutputPortCount];
 
-    /**
-     * Returns information about an output port.
-     *
-     * @param portNumber the number of the output port
-     * @return the output port's information object
-     */
-    public PortInfo getOutputPortInfo(int portNumber) {
-        if (portNumber < 0 || portNumber >= mOutputPortCount) {
-            throw new IllegalArgumentException("portNumber out of range");
+        int index = 0;
+        for (int i = 0; i < mInputPortCount; i++) {
+            portInfoList[index++] = new PortInfo(PortInfo.TYPE_INPUT, i, mInputPortNames[i]);
         }
-        return new PortInfo(PortInfo.TYPE_OUTPUT, portNumber, mOutputPortNames[portNumber]);
+        for (int i = 0; i < mOutputPortCount; i++) {
+            portInfoList[index++] = new PortInfo(PortInfo.TYPE_OUTPUT, i, mOutputPortNames[i]);
+        }
+
+        return portInfoList;
     }
 
     /**
diff --git a/media/java/android/media/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
index bc85f92..a316a44 100644
--- a/media/java/android/media/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -252,6 +252,11 @@
                 mPortClients.put(token, client);
             }
         }
+
+        @Override
+        public MidiDeviceInfo getDeviceInfo() {
+            return mDeviceInfo;
+        }
     };
 
     /* package */ MidiDeviceServer(IMidiManager midiManager, MidiReceiver[] inputPortReceivers,
@@ -279,6 +284,10 @@
         return mServer;
     }
 
+    public IBinder asBinder() {
+        return mServer.asBinder();
+    }
+
     /* package */ void setDeviceInfo(MidiDeviceInfo deviceInfo) {
         if (mDeviceInfo != null) {
             throw new IllegalStateException("setDeviceInfo should only be called once");
diff --git a/media/java/android/media/midi/MidiDeviceService.java b/media/java/android/media/midi/MidiDeviceService.java
index 8b1de3e..ce12a4f 100644
--- a/media/java/android/media/midi/MidiDeviceService.java
+++ b/media/java/android/media/midi/MidiDeviceService.java
@@ -91,7 +91,7 @@
     /**
      * Returns an array of {@link MidiReceiver} for the device's input ports.
      * Subclasses must override this to provide the receivers which will receive
-     * data sent to the device's input ports. An empty array or null should be returned if
+     * data sent to the device's input ports. An empty array should be returned if
      * the device has no input ports.
      * @return array of MidiReceivers
      */
diff --git a/media/java/android/media/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
index 1d3b37a..ff16a57 100644
--- a/media/java/android/media/midi/MidiInputPort.java
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -83,7 +83,18 @@
             if (mOutputStream == null) {
                 throw new IOException("MidiInputPort is closed");
             }
-            int length = MidiPortImpl.packMessage(msg, offset, count, timestamp, mBuffer);
+            int length = MidiPortImpl.packData(msg, offset, count, timestamp, mBuffer);
+            mOutputStream.write(mBuffer, 0, length);
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        synchronized (mBuffer) {
+            if (mOutputStream == null) {
+                throw new IOException("MidiInputPort is closed");
+            }
+            int length = MidiPortImpl.packFlush(mBuffer);
             mOutputStream.write(mBuffer, 0, length);
         }
     }
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 1b98ca5..0ba1744 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -16,6 +16,7 @@
 
 package android.media.midi;
 
+import android.bluetooth.BluetoothDevice;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -38,13 +39,28 @@
  *
  * {@samplecode
  * MidiManager manager = (MidiManager) getSystemService(Context.MIDI_SERVICE);}
- *
- * CANDIDATE FOR PUBLIC API
- * @hide
  */
 public final class MidiManager {
     private static final String TAG = "MidiManager";
 
+    /**
+     * Intent for starting BluetoothMidiService
+     * @hide
+     */
+    public static final String BLUETOOTH_MIDI_SERVICE_INTENT =
+                "android.media.midi.BluetoothMidiService";
+
+    /**
+     * BluetoothMidiService package name
+     */
+    private static final String BLUETOOTH_MIDI_SERVICE_PACKAGE = "com.android.bluetoothmidiservice";
+
+    /**
+     * BluetoothMidiService class name
+     */
+    private static final String BLUETOOTH_MIDI_SERVICE_CLASS =
+                "com.android.bluetoothmidiservice.BluetoothMidiService";
+
     private final Context mContext;
     private final IMidiManager mService;
     private final IBinder mToken = new Binder();
@@ -128,7 +144,7 @@
         /**
          * Called to notify when the status of a MIDI device has changed
          *
-         * @param device a {@link MidiDeviceStatus} for the changed device
+         * @param status a {@link MidiDeviceStatus} for the changed device
          */
         public void onDeviceStatusChanged(MidiDeviceStatus status) {
         }
@@ -148,6 +164,19 @@
     }
 
     /**
+     * Callback class used for receiving the results of {@link #openBluetoothDevice}
+     */
+    abstract public static class BluetoothOpenCallback {
+        /**
+         * Called to respond to a {@link #openBluetoothDevice} request
+         *
+         * @param bluetoothDevice the {@link android.bluetooth.BluetoothDevice} to open
+         * @param device a {@link MidiDevice} for opened device, or null if opening failed
+         */
+        abstract public void onDeviceOpened(BluetoothDevice bluetoothDevice, MidiDevice device);
+    }
+
+    /**
      * @hide
      */
     public MidiManager(Context context, IMidiManager service) {
@@ -217,11 +246,24 @@
         }
     }
 
+    private void sendBluetoothDeviceResponse(final BluetoothDevice bluetoothDevice,
+            final MidiDevice device, final BluetoothOpenCallback callback, Handler handler) {
+        if (handler != null) {
+            handler.post(new Runnable() {
+                    @Override public void run() {
+                        callback.onDeviceOpened(bluetoothDevice, device);
+                    }
+                });
+        } else {
+            callback.onDeviceOpened(bluetoothDevice, device);
+        }
+    }
+
     /**
      * Opens a MIDI device for reading and writing.
      *
      * @param deviceInfo a {@link android.media.midi.MidiDeviceInfo} to open
-     * @param callback a {@link #DeviceOpenCallback} to be called to receive the result
+     * @param callback a {@link MidiManager.DeviceOpenCallback} to be called to receive the result
      * @param handler the {@link android.os.Handler Handler} that will be used for delivering
      *                the result. If handler is null, then the thread used for the
      *                callback is unspecified.
@@ -263,7 +305,7 @@
                         // return immediately to avoid calling sendOpenDeviceResponse below
                         return;
                     } else {
-                        Log.e(TAG, "Unable to bind  service: " + intent);
+                        Log.e(TAG, "Unable to bind service: " + intent);
                     }
                 }
             } else {
@@ -275,6 +317,51 @@
         sendOpenDeviceResponse(deviceInfo, device, callback, handler);
     }
 
+    /**
+     * Opens a Bluetooth MIDI device for reading and writing.
+     *
+     * @param bluetoothDevice a {@link android.bluetooth.BluetoothDevice} to open as a MIDI device
+     * @param callback a {@link MidiManager.BluetoothOpenCallback} to be called to receive the
+     * result
+     * @param handler the {@link android.os.Handler Handler} that will be used for delivering
+     *                the result. If handler is null, then the thread used for the
+     *                callback is unspecified.
+     */
+    public void openBluetoothDevice(final BluetoothDevice bluetoothDevice,
+            final BluetoothOpenCallback callback, final Handler handler) {
+        Intent intent = new Intent(BLUETOOTH_MIDI_SERVICE_INTENT);
+        intent.setComponent(new ComponentName(BLUETOOTH_MIDI_SERVICE_PACKAGE,
+                BLUETOOTH_MIDI_SERVICE_CLASS));
+        intent.putExtra("device", bluetoothDevice);
+        if (!mContext.bindService(intent,
+            new ServiceConnection() {
+                @Override
+                public void onServiceConnected(ComponentName name, IBinder binder) {
+                    IMidiDeviceServer server =
+                            IMidiDeviceServer.Stub.asInterface(binder);
+                    try {
+                        // fetch MidiDeviceInfo from the server
+                        MidiDeviceInfo deviceInfo = server.getDeviceInfo();
+                        MidiDevice device = new MidiDevice(deviceInfo, server, mContext, this);
+                        sendBluetoothDeviceResponse(bluetoothDevice, device, callback, handler);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "remote exception in onServiceConnected");
+                        sendBluetoothDeviceResponse(bluetoothDevice, null, callback, handler);
+                    }
+                }
+
+                @Override
+                public void onServiceDisconnected(ComponentName name) {
+                    // FIXME - anything to do here?
+                }
+            },
+            Context.BIND_AUTO_CREATE))
+        {
+            Log.e(TAG, "Unable to bind service: " + intent);
+            sendBluetoothDeviceResponse(bluetoothDevice, null, callback, handler);
+        }
+    }
+
     /** @hide */
     public MidiDeviceServer createDeviceServer(MidiReceiver[] inputPortReceivers,
             int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
diff --git a/media/java/android/media/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
index 0290a76..7491f3c 100644
--- a/media/java/android/media/midi/MidiOutputPort.java
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -62,12 +62,24 @@
                         // FIXME - inform receivers here?
                     }
 
-                    int offset = MidiPortImpl.getMessageOffset(buffer, count);
-                    int size = MidiPortImpl.getMessageSize(buffer, count);
-                    long timestamp = MidiPortImpl.getMessageTimeStamp(buffer, count);
+                    int packetType = MidiPortImpl.getPacketType(buffer, count);
+                    switch (packetType) {
+                        case MidiPortImpl.PACKET_TYPE_DATA: {
+                            int offset = MidiPortImpl.getDataOffset(buffer, count);
+                            int size = MidiPortImpl.getDataSize(buffer, count);
+                            long timestamp = MidiPortImpl.getPacketTimestamp(buffer, count);
 
-                    // dispatch to all our receivers
-                    mDispatcher.sendWithTimestamp(buffer, offset, size, timestamp);
+                            // dispatch to all our receivers
+                            mDispatcher.sendWithTimestamp(buffer, offset, size, timestamp);
+                            break;
+                        }
+                        case MidiPortImpl.PACKET_TYPE_FLUSH:
+                            mDispatcher.flush();
+                            break;
+                        default:
+                            Log.e(TAG, "Unknown packet type " + packetType);
+                            break;
+                    }
                 }
             } catch (IOException e) {
                 // FIXME report I/O failure?
diff --git a/media/java/android/media/midi/MidiPortImpl.java b/media/java/android/media/midi/MidiPortImpl.java
index 5795045..16fc214 100644
--- a/media/java/android/media/midi/MidiPortImpl.java
+++ b/media/java/android/media/midi/MidiPortImpl.java
@@ -24,6 +24,16 @@
     private static final String TAG = "MidiPort";
 
     /**
+     * Packet type for data packet
+     */
+    public static final int PACKET_TYPE_DATA = 1;
+
+    /**
+     * Packet type for flush packet
+     */
+    public static final int PACKET_TYPE_FLUSH = 2;
+
+    /**
      * Maximum size of a packet that can pass through our ParcelFileDescriptor.
      */
     public static final int MAX_PACKET_SIZE = 1024;
@@ -34,12 +44,17 @@
     private static final int TIMESTAMP_SIZE = 8;
 
     /**
-     * Maximum amount of MIDI data that can be included in a packet
+     * Data packet overhead is timestamp size plus packet type byte
      */
-    public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+    private static final int DATA_PACKET_OVERHEAD = TIMESTAMP_SIZE + 1;
 
     /**
-     * Utility function for packing a MIDI message to be sent through our ParcelFileDescriptor
+     * Maximum amount of MIDI data that can be included in a packet
+     */
+    public static final int MAX_PACKET_DATA_SIZE = MAX_PACKET_SIZE - DATA_PACKET_OVERHEAD;
+
+    /**
+     * Utility function for packing MIDI data to be sent through our ParcelFileDescriptor
      *
      * message byte array contains variable length MIDI message.
      * messageSize is size of variable length MIDI message
@@ -47,46 +62,65 @@
      * dest is buffer to pack into
      * returns size of packed message
      */
-    public static int packMessage(byte[] message, int offset, int size, long timestamp,
+    public static int packData(byte[] message, int offset, int size, long timestamp,
             byte[] dest) {
-        if (size + TIMESTAMP_SIZE > MAX_PACKET_SIZE) {
-            size = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
+        if (size  > MAX_PACKET_DATA_SIZE) {
+            size = MAX_PACKET_DATA_SIZE;
         }
-        // message data goes first
-        System.arraycopy(message, offset, dest, 0, size);
+        int length = 0;
+        // packet type goes first
+        dest[length++] = PACKET_TYPE_DATA;
+        // data goes next
+        System.arraycopy(message, offset, dest, length, size);
+        length += size;
 
         // followed by timestamp
         for (int i = 0; i < TIMESTAMP_SIZE; i++) {
-            dest[size++] = (byte)timestamp;
+            dest[length++] = (byte)timestamp;
             timestamp >>= 8;
         }
 
-        return size;
+        return length;
     }
 
     /**
-     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * Utility function for packing a flush command to be sent through our ParcelFileDescriptor
+     */
+    public static int packFlush(byte[] dest) {
+        dest[0] = PACKET_TYPE_FLUSH;
+        return 1;
+    }
+
+    /**
+     * Returns the packet type (PACKET_TYPE_DATA or PACKET_TYPE_FLUSH)
+     */
+    public static int getPacketType(byte[] buffer, int bufferLength) {
+        return buffer[0];
+    }
+
+    /**
+     * Utility function for unpacking MIDI data received from our ParcelFileDescriptor
      * returns the offset of the MIDI message in packed buffer
      */
-    public static int getMessageOffset(byte[] buffer, int bufferLength) {
-        // message is at the beginning
-        return 0;
+    public static int getDataOffset(byte[] buffer, int bufferLength) {
+        // data follows packet type byte
+        return 1;
     }
 
     /**
-     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * Utility function for unpacking MIDI data received from our ParcelFileDescriptor
      * returns size of MIDI data in packed buffer
      */
-    public static int getMessageSize(byte[] buffer, int bufferLength) {
+    public static int getDataSize(byte[] buffer, int bufferLength) {
         // message length is total buffer length minus size of the timestamp
-        return bufferLength - TIMESTAMP_SIZE;
+        return bufferLength - DATA_PACKET_OVERHEAD;
     }
 
     /**
-     * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
+     * Utility function for unpacking MIDI data received from our ParcelFileDescriptor
      * unpacks timestamp from packed buffer
      */
-    public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+    public static long getPacketTimestamp(byte[] buffer, int bufferLength) {
         // timestamp is at end of the packet
         int offset = bufferLength;
         long timestamp = 0;
diff --git a/media/java/android/media/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java
index 6f4c266..d069075 100644
--- a/media/java/android/media/midi/MidiReceiver.java
+++ b/media/java/android/media/midi/MidiReceiver.java
@@ -42,6 +42,13 @@
             throws IOException;
 
     /**
+     * Instructs the receiver to discard all pending events.
+     * @throws IOException
+     */
+    public void flush() throws IOException {
+    }
+
+    /**
      * Returns the maximum size of a message this receiver can receive.
      * Defaults to {@link java.lang.Integer#MAX_VALUE} unless overridden.
      * @return maximum message size
diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl
index 7a023d6..86c0e5d 100644
--- a/media/java/android/media/tv/ITvInputClient.aidl
+++ b/media/java/android/media/tv/ITvInputClient.aidl
@@ -40,4 +40,7 @@
     void onContentAllowed(int seq);
     void onContentBlocked(in String rating, int seq);
     void onLayoutSurface(int left, int top, int right, int bottom, int seq);
+    void onTimeShiftStatusChanged(int status, int seq);
+    void onTimeShiftStartPositionChanged(long timeMs, int seq);
+    void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
 }
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 21549c9..b6491d8 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -74,6 +74,12 @@
 
     void requestUnblockContent(in IBinder sessionToken, in String unblockedRating, int userId);
 
+    void timeShiftPause(in IBinder sessionToken, int userId);
+    void timeShiftResume(in IBinder sessionToken, int userId);
+    void timeShiftSeekTo(in IBinder sessionToken, long timeMs, int userId);
+    void timeShiftSetPlaybackRate(in IBinder sessionToken, float rate, int audioMode, int userId);
+    void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId);
+
     // For TV input hardware binding
     List<TvInputHardwareInfo> getHardwareList();
     ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback,
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index 1aad2fa..a054200 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -46,4 +46,10 @@
     void removeOverlayView();
 
     void requestUnblockContent(in String unblockedRating);
+
+    void timeShiftPause();
+    void timeShiftResume();
+    void timeShiftSeekTo(long timeMs);
+    void timeShiftSetPlaybackRate(float rate, int audioMode);
+    void timeShiftEnablePositionTracking(boolean enable);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl
index 063d10d..e936810 100644
--- a/media/java/android/media/tv/ITvInputSessionCallback.aidl
+++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl
@@ -37,4 +37,7 @@
     void onContentAllowed();
     void onContentBlocked(in String rating);
     void onLayoutSurface(int left, int top, int right, int bottom);
+    void onTimeShiftStatusChanged(int status);
+    void onTimeShiftStartPositionChanged(long timeMs);
+    void onTimeShiftCurrentPositionChanged(long timeMs);
 }
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 94c9690..a3442e3 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -57,6 +57,11 @@
     private static final int DO_RELAYOUT_OVERLAY_VIEW = 11;
     private static final int DO_REMOVE_OVERLAY_VIEW = 12;
     private static final int DO_REQUEST_UNBLOCK_CONTENT = 13;
+    private static final int DO_TIME_SHIFT_PAUSE = 14;
+    private static final int DO_TIME_SHIFT_RESUME = 15;
+    private static final int DO_TIME_SHIFT_SEEK_TO = 16;
+    private static final int DO_TIME_SHIFT_SET_PLAYBACK_RATE = 17;
+    private static final int DO_TIME_SHIFT_ENABLE_POSITION_TRACKING = 18;
 
     private final HandlerCaller mCaller;
 
@@ -153,6 +158,26 @@
                 mTvInputSessionImpl.unblockContent((String) msg.obj);
                 break;
             }
+            case DO_TIME_SHIFT_PAUSE: {
+                mTvInputSessionImpl.timeShiftPause();
+                break;
+            }
+            case DO_TIME_SHIFT_RESUME: {
+                mTvInputSessionImpl.timeShiftResume();
+                break;
+            }
+            case DO_TIME_SHIFT_SEEK_TO: {
+                mTvInputSessionImpl.timeShiftSeekTo((Long) msg.obj);
+                break;
+            }
+            case DO_TIME_SHIFT_SET_PLAYBACK_RATE: {
+                mTvInputSessionImpl.timeShiftSetPlaybackRate((Float) msg.obj, msg.arg1);
+                break;
+            }
+            case DO_TIME_SHIFT_ENABLE_POSITION_TRACKING: {
+                mTvInputSessionImpl.timeShiftEnablePositionTracking((Boolean) msg.obj);
+                break;
+            }
             default: {
                 Log.w(TAG, "Unhandled message code: " + msg.what);
                 break;
@@ -242,6 +267,34 @@
                 DO_REQUEST_UNBLOCK_CONTENT, unblockedRating));
     }
 
+    @Override
+    public void timeShiftPause() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_TIME_SHIFT_PAUSE));
+    }
+
+    @Override
+    public void timeShiftResume() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_TIME_SHIFT_RESUME));
+    }
+
+    @Override
+    public void timeShiftSeekTo(long timeMs) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_TIME_SHIFT_SEEK_TO,
+                Long.valueOf(timeMs)));
+    }
+
+    @Override
+    public void timeShiftSetPlaybackRate(float rate, int audioMode) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageIO(DO_TIME_SHIFT_SET_PLAYBACK_RATE,
+                audioMode, Float.valueOf(rate)));
+    }
+
+    @Override
+    public void timeShiftEnablePositionTracking(boolean enable) {
+        mCaller.executeOrSendMessage(mCaller.obtainMessageO(
+                DO_TIME_SHIFT_ENABLE_POSITION_TRACKING, Boolean.valueOf(enable)));
+    }
+
     private final class TvInputEventReceiver extends InputEventReceiver {
         public TvInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f55299e..ee2a233 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -18,6 +18,7 @@
 
 import android.annotation.SystemApi;
 import android.graphics.Rect;
+import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -51,7 +52,7 @@
     private static final String TAG = "TvInputManager";
 
     static final int VIDEO_UNAVAILABLE_REASON_START = 0;
-    static final int VIDEO_UNAVAILABLE_REASON_END = 3;
+    static final int VIDEO_UNAVAILABLE_REASON_END = 4;
 
     /**
      * A generic reason. Video is not available due to an unspecified error.
@@ -69,7 +70,38 @@
      * Video is not available because the TV input stopped the playback temporarily to buffer more
      * data.
      */
-    public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = VIDEO_UNAVAILABLE_REASON_END;
+    public static final int VIDEO_UNAVAILABLE_REASON_BUFFERING = 3;
+    /**
+     * Video is not available because the current program is audio-only.
+     */
+    public static final int VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY = VIDEO_UNAVAILABLE_REASON_END;
+
+    private static final int TIME_SHIFT_STATUS_START = 0;
+    private static final int TIME_SHIFT_STATUS_END = 3;
+
+    /**
+     * Status prior to calling {@link TvInputService.Session#notifyTimeShiftStatusChanged}.
+     */
+    public static final int TIME_SHIFT_STATUS_UNKNOWN = TIME_SHIFT_STATUS_START;
+
+    /**
+     * The TV input does not support time shifting.
+     */
+    public static final int TIME_SHIFT_STATUS_UNSUPPORTED = 1;
+
+    /**
+     * Time shifting is currently not available but might work again later.
+     */
+    public static final int TIME_SHIFT_STATUS_UNAVAILABLE = 2;
+
+    /**
+     * Time shifting is currently available. In this status, the application assumes it can
+     * pause/resume playback, seek to a specified time position and set playback rate and audio
+     * mode.
+     */
+    public static final int TIME_SHIFT_STATUS_AVAILABLE = TIME_SHIFT_STATUS_END;
+
+    public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
 
     /**
      * The TV input is in unknown state.
@@ -271,13 +303,14 @@
         /**
          * This is called when the video is not available, so the TV input stops the playback.
          *
-         * @param session A {@link TvInputManager.Session} associated with this callback
+         * @param session A {@link TvInputManager.Session} associated with this callback.
          * @param reason The reason why the TV input stopped the playback:
          * <ul>
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_UNKNOWN}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
+         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
          * </ul>
          */
         public void onVideoUnavailable(Session session, int reason) {
@@ -287,7 +320,7 @@
          * This is called when the current program content turns out to be allowed to watch since
          * its content rating is not blocked by parental controls.
          *
-         * @param session A {@link TvInputManager.Session} associated with this callback
+         * @param session A {@link TvInputManager.Session} associated with this callback.
          */
         public void onContentAllowed(Session session) {
         }
@@ -296,7 +329,7 @@
          * This is called when the current program content turns out to be not allowed to watch
          * since its content rating is blocked by parental controls.
          *
-         * @param session A {@link TvInputManager.Session} associated with this callback
+         * @param session A {@link TvInputManager.Session} associated with this callback.
          * @param rating The content ration of the blocked program.
          */
         public void onContentBlocked(Session session, TvContentRating rating) {
@@ -306,7 +339,7 @@
          * This is called when {@link TvInputService.Session#layoutSurface} is called to change the
          * layout of surface.
          *
-         * @param session A {@link TvInputManager.Session} associated with this callback
+         * @param session A {@link TvInputManager.Session} associated with this callback.
          * @param left Left position.
          * @param top Top position.
          * @param right Right position.
@@ -328,6 +361,46 @@
         @SystemApi
         public void onSessionEvent(Session session, String eventType, Bundle eventArgs) {
         }
+
+        /**
+         * This is called when the time shift status is changed.
+         *
+         * @param session A {@link TvInputManager.Session} associated with this callback.
+         * @param status The current time shift status. Should be one of the followings.
+         * <ul>
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
+         * </ul>
+         */
+        public void onTimeShiftStatusChanged(Session session, int status) {
+        }
+
+        /**
+         * This is called when the start playback position is changed.
+         * <p>
+         * The start playback position of the time shifted program should be adjusted when the TV
+         * input cannot retain the whole recorded program due to some reason (e.g. limitation on
+         * storage space). This is necessary to prevent the application from allowing the user to
+         * seek to a time position that is not reachable.
+         * </p>
+         *
+         * @param session A {@link TvInputManager.Session} associated with this callback.
+         * @param timeMs The start playback position of the time shifted program, in milliseconds
+         *            since the epoch.
+         */
+        public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
+        }
+
+        /**
+         * This is called when the current playback position is changed.
+         *
+         * @param session A {@link TvInputManager.Session} associated with this callback.
+         * @param timeMs The current playback position of the time shifted program, in milliseconds
+         *            since the epoch.
+         */
+        public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
+        }
     }
 
     private static final class SessionCallbackRecord {
@@ -450,6 +523,33 @@
                 }
             });
         }
+
+        void postTimeShiftStatusChanged(final int status) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onTimeShiftStatusChanged(mSession, status);
+                }
+            });
+        }
+
+        void postTimeShiftStartPositionChanged(final long timeMs) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onTimeShiftStartPositionChanged(mSession, timeMs);
+                }
+            });
+        }
+
+        void postTimeShiftCurrentPositionChanged(final long timeMs) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mSessionCallback.onTimeShiftCurrentPositionChanged(mSession, timeMs);
+                }
+            });
+        }
     }
 
     /**
@@ -718,6 +818,42 @@
                     record.postSessionEvent(eventType, eventArgs);
                 }
             }
+
+            @Override
+            public void onTimeShiftStatusChanged(int status, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postTimeShiftStatusChanged(status);
+                }
+            }
+
+            @Override
+            public void onTimeShiftStartPositionChanged(long timeMs, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postTimeShiftStartPositionChanged(timeMs);
+                }
+            }
+
+            @Override
+            public void onTimeShiftCurrentPositionChanged(long timeMs, int seq) {
+                synchronized (mSessionCallbackRecordMap) {
+                    SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
+                    if (record == null) {
+                        Log.e(TAG, "Callback not found for seq " + seq);
+                        return;
+                    }
+                    record.postTimeShiftCurrentPositionChanged(timeMs);
+                }
+            }
         };
         mManagerCallback = new ITvInputManagerCallback.Stub() {
             @Override
@@ -774,7 +910,7 @@
                 }
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "TvInputManager initialization failed: " + e);
+            Log.e(TAG, "TvInputManager initialization failed", e);
         }
     }
 
@@ -1171,22 +1307,22 @@
         private TvInputEventSender mSender;
         private InputChannel mChannel;
 
-        private final Object mTrackLock = new Object();
-        // @GuardedBy("mTrackLock")
+        private final Object mMetadataLock = new Object();
+        // @GuardedBy("mMetadataLock")
         private final List<TvTrackInfo> mAudioTracks = new ArrayList<TvTrackInfo>();
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private final List<TvTrackInfo> mVideoTracks = new ArrayList<TvTrackInfo>();
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private final List<TvTrackInfo> mSubtitleTracks = new ArrayList<TvTrackInfo>();
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private String mSelectedAudioTrackId;
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private String mSelectedVideoTrackId;
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private String mSelectedSubtitleTrackId;
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private int mVideoWidth;
-        // @GuardedBy("mTrackLock")
+        // @GuardedBy("mMetadataLock")
         private int mVideoHeight;
 
         private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId,
@@ -1322,7 +1458,7 @@
                 Log.w(TAG, "The session has been already released");
                 return;
             }
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 mAudioTracks.clear();
                 mVideoTracks.clear();
                 mSubtitleTracks.clear();
@@ -1367,7 +1503,7 @@
          * @see #getTracks
          */
         public void selectTrack(int type, String trackId) {
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 if (type == TvTrackInfo.TYPE_AUDIO) {
                     if (trackId != null && !containsTrack(mAudioTracks, trackId)) {
                         Log.w(TAG, "Invalid audio trackId: " + trackId);
@@ -1416,7 +1552,7 @@
          * @return the list of tracks for the given type.
          */
         public List<TvTrackInfo> getTracks(int type) {
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 if (type == TvTrackInfo.TYPE_AUDIO) {
                     if (mAudioTracks == null) {
                         return null;
@@ -1445,7 +1581,7 @@
          * @see #selectTrack
          */
         public String getSelectedTrack(int type) {
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 if (type == TvTrackInfo.TYPE_AUDIO) {
                     return mSelectedAudioTrackId;
                 } else if (type == TvTrackInfo.TYPE_VIDEO) {
@@ -1462,7 +1598,7 @@
          * there is an update.
          */
         boolean updateTracks(List<TvTrackInfo> tracks) {
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 mAudioTracks.clear();
                 mVideoTracks.clear();
                 mSubtitleTracks.clear();
@@ -1485,7 +1621,7 @@
          * Returns true if there is an update.
          */
         boolean updateTrackSelection(int type, String trackId) {
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 if (type == TvTrackInfo.TYPE_AUDIO && trackId != mSelectedAudioTrackId) {
                     mSelectedAudioTrackId = trackId;
                     return true;
@@ -1509,7 +1645,7 @@
          * track.
          */
         TvTrackInfo getVideoTrackToNotify() {
-            synchronized (mTrackLock) {
+            synchronized (mMetadataLock) {
                 if (!mVideoTracks.isEmpty() && mSelectedVideoTrackId != null) {
                     for (TvTrackInfo track : mVideoTracks) {
                         if (track.getId().equals(mSelectedVideoTrackId)) {
@@ -1528,6 +1664,98 @@
         }
 
         /**
+         * Pauses the playback. Call {@link #timeShiftResume()} to restart the playback.
+         */
+        void timeShiftPause() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.timeShiftPause(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Resumes the playback. No-op if it is already playing the channel.
+         */
+        void timeShiftResume() {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.timeShiftResume(mToken, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Seeks to a specified time position.
+         * <p>
+         * Normally, the position is given within range between the start and the current time,
+         * inclusively.
+         *
+         * @param timeMs The time position to seek to, in milliseconds since the epoch.
+         * @see TvView.TimeShiftPositionCallback#onTimeShiftStartPositionChanged
+         */
+        void timeShiftSeekTo(long timeMs) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.timeShiftSeekTo(mToken, timeMs, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Sets playback rate and audio mode.
+         *
+         * @param rate The ratio between desired playback rate and normal one.
+         * @param audioMode Audio playback mode. Must be one of the supported audio modes:
+         * <ul>
+         * <li> {@link android.media.MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
+         * </ul>
+         */
+        void timeShiftSetPlaybackRate(float rate, int audioMode) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            if (audioMode != MediaPlayer.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE) {
+                throw new IllegalArgumentException("Unknown audio playback mode " + audioMode);
+            }
+            try {
+                mService.timeShiftSetPlaybackRate(mToken, rate, audioMode, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
+         * Enable/disable position tracking.
+         *
+         * @param enable {@code true} to enable tracking, {@code false} otherwise.
+         */
+        void timeShiftEnablePositionTracking(boolean enable) {
+            if (mToken == null) {
+                Log.w(TAG, "The session has been already released");
+                return;
+            }
+            try {
+                mService.timeShiftEnablePositionTracking(mToken, enable, mUserId);
+            } catch (RemoteException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        /**
          * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
          * TvInputService.Session.appPrivateCommand()} on the current TvView.
          *
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 8ed383a..343ffcb 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -235,7 +235,9 @@
      * Base class for derived classes to implement to provide a TV input session.
      */
     public abstract static class Session implements KeyEvent.Callback {
-        private static final int DETACH_OVERLAY_VIEW_TIMEOUT = 5000;
+        private static final int DETACH_OVERLAY_VIEW_TIMEOUT_MS = 5000;
+        private static final int POSITION_UPDATE_INTERVAL_MS = 1000;
+
         private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
         private final WindowManager mWindowManager;
         final Handler mHandler;
@@ -248,6 +250,10 @@
         private boolean mOverlayViewEnabled;
         private IBinder mWindowToken;
         private Rect mOverlayFrame;
+        private long mStartPositionMs;
+        private long mCurrentPositionMs;
+        private final TimeShiftPositionTrackingRunnable
+                mTimeShiftPositionTrackingRunnable = new TimeShiftPositionTrackingRunnable();
 
         private final Object mLock = new Object();
         // @GuardedBy("mLock")
@@ -264,6 +270,7 @@
             mContext = context;
             mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
             mHandler = new Handler(context.getMainLooper());
+            mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
         }
 
         /**
@@ -313,7 +320,7 @@
                             mSessionCallback.onSessionEvent(eventType, eventArgs);
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in sending event (event=" + eventType + ")");
+                        Log.w(TAG, "error in sending event (event=" + eventType + ")", e);
                     }
                 }
             });
@@ -334,7 +341,7 @@
                             mSessionCallback.onChannelRetuned(channelUri);
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyChannelRetuned");
+                        Log.w(TAG, "error in notifyChannelRetuned", e);
                     }
                 }
             });
@@ -373,7 +380,7 @@
                             mSessionCallback.onTracksChanged(tracks);
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyTracksChanged");
+                        Log.w(TAG, "error in notifyTracksChanged", e);
                     }
                 }
             });
@@ -403,7 +410,7 @@
                             mSessionCallback.onTrackSelected(type, trackId);
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyTrackSelected");
+                        Log.w(TAG, "error in notifyTrackSelected", e);
                     }
                 }
             });
@@ -426,7 +433,7 @@
                             mSessionCallback.onVideoAvailable();
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyVideoAvailable");
+                        Log.w(TAG, "error in notifyVideoAvailable", e);
                     }
                 }
             });
@@ -443,6 +450,7 @@
          *            <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
          *            <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
          *            <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
+         *            <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
          *            </ul>
          * @see #notifyVideoAvailable
          */
@@ -460,7 +468,7 @@
                             mSessionCallback.onVideoUnavailable(reason);
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyVideoUnavailable");
+                        Log.w(TAG, "error in notifyVideoUnavailable", e);
                     }
                 }
             });
@@ -501,7 +509,7 @@
                             mSessionCallback.onContentAllowed();
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyContentAllowed");
+                        Log.w(TAG, "error in notifyContentAllowed", e);
                     }
                 }
             });
@@ -543,7 +551,81 @@
                             mSessionCallback.onContentBlocked(rating.flattenToString());
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in notifyContentBlocked");
+                        Log.w(TAG, "error in notifyContentBlocked", e);
+                    }
+                }
+            });
+        }
+
+        /**
+         * Informs the application that the time shift status is changed.
+         * <p>
+         * Prior to calling this method, the application assumes the status
+         * {@link TvInputManager#TIME_SHIFT_STATUS_UNKNOWN}. Right after the session is created, it
+         * is important to invoke the method with the status
+         * {@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE} if the implementation does support
+         * time shifting, or {@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED} otherwise. Failure
+         * to notifying the current status change immediately might result in an undesirable
+         * behavior in the application such as hiding the play controls.
+         * </p><p>
+         * If the status {@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE} is reported, the
+         * application assumes it can pause/resume playback, seek to a specified time position and
+         * set playback rate and audio mode. The implementation should override
+         * {@link #onTimeShiftPause}, {@link #onTimeShiftResume}, {@link #onTimeShiftSeekTo},
+         * {@link #onTimeShiftGetStartPosition}, {@link #onTimeShiftGetCurrentPosition} and
+         * {@link #onTimeShiftSetPlaybackRate}.
+         * </p>
+         *
+         * @param status The current time shift status. Should be one of the followings.
+         * <ul>
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
+         * </ul>
+         */
+        public void notifyTimeShiftStatusChanged(final int status) {
+            executeOrPostRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyTimeShiftStatusChanged");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onTimeShiftStatusChanged(status);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyTimeShiftStatusChanged", e);
+                    }
+                }
+            });
+        }
+
+        private void notifyTimeShiftStartPositionChanged(final long timeMs) {
+            executeOrPostRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyTimeShiftStartPositionChanged");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onTimeShiftStartPositionChanged(timeMs);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyTimeShiftStartPositionChanged", e);
+                    }
+                }
+            });
+        }
+
+        private void notifyTimeShiftCurrentPositionChanged(final long timeMs) {
+            executeOrPostRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        if (DEBUG) Log.d(TAG, "notifyTimeShiftCurrentPositionChanged");
+                        if (mSessionCallback != null) {
+                            mSessionCallback.onTimeShiftCurrentPositionChanged(timeMs);
+                        }
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "error in notifyTimeShiftCurrentPositionChanged", e);
                     }
                 }
             });
@@ -576,7 +658,7 @@
                             mSessionCallback.onLayoutSurface(left, top, right, bottom);
                         }
                     } catch (RemoteException e) {
-                        Log.w(TAG, "error in layoutSurface");
+                        Log.w(TAG, "error in layoutSurface", e);
                     }
                 }
             });
@@ -621,7 +703,7 @@
          * When {@code setSurface(null)} is called, the implementation should stop using the Surface
          * object previously given and release any references to it.
          *
-         * @param surface possibly {@code null} {@link Surface} an application passes to this TV
+         * @param surface possibly {@code null} {@link Surface} the application passes to this TV
          *            input session.
          * @return {@code true} if the surface was set, {@code false} otherwise.
          */
@@ -640,10 +722,10 @@
         }
 
         /**
-         * Called when a size of an overlay view is changed by an application. Even when the overlay
-         * view is disabled by {@link #setOverlayViewEnabled}, this is called. The size is same as
-         * the size of {@link Surface} in general. Once {@link #layoutSurface} is called, the sizes
-         * of {@link Surface} and the overlay view can be different.
+         * Called when a size of an overlay view is changed by the application. Even when the
+         * overlay view is disabled by {@link #setOverlayViewEnabled}, this is called. The size is
+         * same as the size of {@link Surface} in general. Once {@link #layoutSurface} is called,
+         * the sizes of {@link Surface} and the overlay view can be different.
          *
          * @param width The width of the overlay view.
          * @param height The height of the overlay view.
@@ -746,7 +828,7 @@
         }
 
         /**
-         * Called when an application requests to create an overlay view. Each session
+         * Called when the application requests to create an overlay view. Each session
          * implementation can override this method and return its own view.
          *
          * @return a view attached to the overlay window
@@ -756,6 +838,100 @@
         }
 
         /**
+         * Called when the application requests to pause playback.
+         *
+         * @see #onTimeShiftResume
+         * @see #onTimeShiftSeekTo
+         * @see #onTimeShiftSetPlaybackRate
+         * @see #onTimeShiftGetStartPosition
+         * @see #onTimeShiftGetCurrentPosition
+         */
+        public void onTimeShiftPause() {
+        }
+
+        /**
+         * Called when the application requests to resume playback.
+         *
+         * @see #onTimeShiftPause
+         * @see #onTimeShiftSeekTo
+         * @see #onTimeShiftSetPlaybackRate
+         * @see #onTimeShiftGetStartPosition
+         * @see #onTimeShiftGetCurrentPosition
+         */
+        public void onTimeShiftResume() {
+        }
+
+        /**
+         * Called when the application requests to seek to a specified time position. Normally, the
+         * position is given within range between the start and the current time, inclusively. The
+         * implementation is expected to seek to the nearest time position if the given position is
+         * not in the range.
+         *
+         * @param timeMs The time position to seek to, in milliseconds since the epoch.
+         * @see #onTimeShiftResume
+         * @see #onTimeShiftPause
+         * @see #onTimeShiftSetPlaybackRate
+         * @see #onTimeShiftGetStartPosition
+         * @see #onTimeShiftGetCurrentPosition
+         */
+        public void onTimeShiftSeekTo(long timeMs) {
+        }
+
+        /**
+         * Called when the application sets playback rate and audio mode.
+         *
+         * @param rate The ratio between desired playback rate and normal one.
+         * @param audioMode Audio playback mode. Must be one of the supported audio modes:
+         * <ul>
+         * <li> {@link android.media.MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
+         * </ul>
+         * @see #onTimeShiftResume
+         * @see #onTimeShiftPause
+         * @see #onTimeShiftSeekTo
+         * @see #onTimeShiftGetStartPosition
+         * @see #onTimeShiftGetCurrentPosition
+         */
+        public void onTimeShiftSetPlaybackRate(float rate, int audioMode) {
+        }
+
+        /**
+         * Returns the start playback position for time shifting, in milliseconds since the epoch.
+         * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
+         * moment.
+         * <p>
+         * The start playback position of the time shifted program should be adjusted when the
+         * implementation cannot retain the whole recorded program due to some reason (e.g.
+         * limitation on storage space). It is the earliest possible time position that the user can
+         * seek to, thus failure to notifying its change immediately might result in bad experience
+         * where the application allows the user to seek to an invalid time position.
+         * </p>
+         *
+         * @see #onTimeShiftResume
+         * @see #onTimeShiftPause
+         * @see #onTimeShiftSeekTo
+         * @see #onTimeShiftSetPlaybackRate
+         * @see #onTimeShiftGetCurrentPosition
+         */
+        public long onTimeShiftGetStartPosition() {
+            return TvInputManager.TIME_SHIFT_INVALID_TIME;
+        }
+
+        /**
+         * Returns the current playback position for time shifting, in milliseconds since the epoch.
+         * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
+         * moment.
+         *
+         * @see #onTimeShiftResume
+         * @see #onTimeShiftPause
+         * @see #onTimeShiftSeekTo
+         * @see #onTimeShiftSetPlaybackRate
+         * @see #onTimeShiftGetStartPosition
+         */
+        public long onTimeShiftGetCurrentPosition() {
+            return TvInputManager.TIME_SHIFT_INVALID_TIME;
+        }
+
+        /**
          * Default implementation of {@link android.view.KeyEvent.Callback#onKeyDown(int, KeyEvent)
          * KeyEvent.Callback.onKeyDown()}: always returns false (doesn't handle the event).
          * <p>
@@ -887,6 +1063,7 @@
             // Removes the overlay view lastly so that any hanging on the main thread can be handled
             // in {@link #scheduleOverlayViewCleanup}.
             removeOverlayView(true);
+            mHandler.removeCallbacks(mTimeShiftPositionTrackingRunnable);
         }
 
         /**
@@ -930,6 +1107,7 @@
          * Calls {@link #onTune}.
          */
         void tune(Uri channelUri, Bundle params) {
+            mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
             onTune(channelUri, params);
             // TODO: Handle failure.
         }
@@ -967,7 +1145,7 @@
          * Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach
          * to the overlay window.
          *
-         * @param windowToken A window token of an application.
+         * @param windowToken A window token of the application.
          * @param frame A position of the overlay view.
          */
         void createOverlayView(IBinder windowToken, Rect frame) {
@@ -1059,6 +1237,49 @@
         }
 
         /**
+         * Calls {@link #onTimeShiftPause}.
+         */
+        void timeShiftPause() {
+            onTimeShiftPause();
+        }
+
+        /**
+         * Calls {@link #onTimeShiftResume}.
+         */
+        void timeShiftResume() {
+            onTimeShiftResume();
+        }
+
+        /**
+         * Calls {@link #onTimeShiftSeekTo}.
+         */
+        void timeShiftSeekTo(long timeMs) {
+            onTimeShiftSeekTo(timeMs);
+        }
+
+        /**
+         * Calls {@link #onTimeShiftSetPlaybackRate}.
+         */
+        void timeShiftSetPlaybackRate(float rate, int audioMode) {
+            onTimeShiftSetPlaybackRate(rate, audioMode);
+        }
+
+        /**
+         * Enable/disable position tracking.
+         *
+         * @param enable {@code true} to enable tracking, {@code false} otherwise.
+         */
+        void timeShiftEnablePositionTracking(boolean enable) {
+            if (enable) {
+                mHandler.post(mTimeShiftPositionTrackingRunnable);
+            } else {
+                mHandler.removeCallbacks(mTimeShiftPositionTrackingRunnable);
+                mStartPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+                mCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+            }
+        }
+
+        /**
          * Schedules a task which checks whether the overlay view is detached and kills the process
          * if it is not. Note that this method is expected to be called in a non-main thread.
          */
@@ -1085,7 +1306,7 @@
                 }
                 isNavigationKey = isNavigationKey(keyEvent.getKeyCode());
                 // When media keys and KEYCODE_MEDIA_AUDIO_TRACK are dispatched to ViewRootImpl,
-                // ViewRootImpl always consumes the keys. In this case, an application loses
+                // ViewRootImpl always consumes the keys. In this case, the application loses
                 // a chance to handle media keys. Therefore, media keys are not dispatched to
                 // ViewRootImpl.
                 skipDispatchToOverlayView = KeyEvent.isMediaKey(keyEvent.getKeyCode())
@@ -1154,12 +1375,31 @@
             }
         }
 
+        private final class TimeShiftPositionTrackingRunnable implements Runnable {
+            @Override
+            public void run() {
+                long startPositionMs = onTimeShiftGetStartPosition();
+                if (mStartPositionMs != startPositionMs) {
+                    mStartPositionMs = startPositionMs;
+                    notifyTimeShiftStartPositionChanged(startPositionMs);
+                }
+                long currentPositionMs = onTimeShiftGetCurrentPosition();
+                if (mCurrentPositionMs != currentPositionMs) {
+                    mCurrentPositionMs = currentPositionMs;
+                    notifyTimeShiftCurrentPositionChanged(currentPositionMs);
+                }
+                mHandler.removeCallbacks(mTimeShiftPositionTrackingRunnable);
+                mHandler.postDelayed(mTimeShiftPositionTrackingRunnable,
+                        POSITION_UPDATE_INTERVAL_MS);
+            }
+        }
+
         private final class OverlayViewCleanUpTask extends AsyncTask<View, Void, Void> {
             @Override
             protected Void doInBackground(View... views) {
                 View overlayViewParent = views[0];
                 try {
-                    Thread.sleep(DETACH_OVERLAY_VIEW_TIMEOUT);
+                    Thread.sleep(DETACH_OVERLAY_VIEW_TIMEOUT_MS);
                 } catch (InterruptedException e) {
                     return null;
                 }
@@ -1286,6 +1526,7 @@
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
+         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
          * </ul>
          */
         public void onHardwareVideoUnavailable(int reason) { }
@@ -1326,7 +1567,7 @@
                 try {
                     mCallbacks.getBroadcastItem(i).addHardwareTvInput(deviceId, inputInfo);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Error while broadcasting.", e);
+                    Log.e(TAG, "error in broadcastAddHardwareTvInput", e);
                 }
             }
             mCallbacks.finishBroadcast();
@@ -1338,7 +1579,7 @@
                 try {
                     mCallbacks.getBroadcastItem(i).addHdmiTvInput(id, inputInfo);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Error while broadcasting.", e);
+                    Log.e(TAG, "error in broadcastAddHdmiTvInput", e);
                 }
             }
             mCallbacks.finishBroadcast();
@@ -1350,7 +1591,7 @@
                 try {
                     mCallbacks.getBroadcastItem(i).removeTvInput(inputId);
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Error while broadcasting.", e);
+                    Log.e(TAG, "error in broadcastRemoveTvInput", e);
                 }
             }
             mCallbacks.finishBroadcast();
@@ -1371,7 +1612,7 @@
                             // Failed to create a session.
                             cb.onSessionCreated(null, null);
                         } catch (RemoteException e) {
-                            Log.e(TAG, "error in onSessionCreated");
+                            Log.e(TAG, "error in onSessionCreated", e);
                         }
                         return;
                     }
@@ -1392,7 +1633,7 @@
                             try {
                                 cb.onSessionCreated(null, null);
                             } catch (RemoteException e) {
-                                Log.e(TAG, "error in onSessionCreated");
+                                Log.e(TAG, "error in onSessionCreated", e);
                             }
                             return;
                         }
@@ -1423,7 +1664,7 @@
                     try {
                         cb.onSessionCreated(stub, hardwareSessionToken);
                     } catch (RemoteException e) {
-                        Log.e(TAG, "error in onSessionCreated");
+                        Log.e(TAG, "error in onSessionCreated", e);
                     }
                     if (sessionImpl != null) {
                         sessionImpl.initialize(cb);
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 6fc1b82..024ffd1 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -103,6 +103,7 @@
     private int mSurfaceViewRight;
     private int mSurfaceViewTop;
     private int mSurfaceViewBottom;
+    private TimeShiftPositionCallback mTimeShiftPositionCallback;
 
     private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
         @Override
@@ -173,8 +174,8 @@
     /**
      * Sets the callback to be invoked when an event is dispatched to this TvView.
      *
-     * @param callback The callback to receive events. A value of {@code null} removes any existing
-     *            callbacks.
+     * @param callback The callback to receive events. A value of {@code null} removes the existing
+     *            callback.
      */
     public void setCallback(TvInputCallback callback) {
         mCallback = callback;
@@ -420,6 +421,70 @@
     }
 
     /**
+     * Pauses playback. No-op if it is already paused. Call {@link #timeShiftResume} to resume.
+     */
+    public void timeShiftPause() {
+        if (mSession != null) {
+            mSession.timeShiftPause();
+        }
+    }
+
+    /**
+     * Resumes playback. No-op if it is already resumed. Call {@link #timeShiftPause} to pause.
+     */
+    public void timeShiftResume() {
+        if (mSession != null) {
+            mSession.timeShiftResume();
+        }
+    }
+
+    /**
+     * Seeks to a specified time position. {@code timeMs} must be equal to or greater than the start
+     * position returned by {@link TimeShiftPositionCallback#onTimeShiftStartPositionChanged} and
+     * equal to or less than the current time.
+     *
+     * @param timeMs The time position to seek to, in milliseconds since the epoch.
+     */
+    public void timeShiftSeekTo(long timeMs) {
+        if (mSession != null) {
+            mSession.timeShiftSeekTo(timeMs);
+        }
+    }
+
+    /**
+     * Sets playback rate and audio mode.
+     *
+     * @param rate The ratio between desired playback rate and normal one.
+     * @param audioMode Audio playback mode. Must be one of the supported audio modes:
+     * <ul>
+     * <li> {@link android.media.MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
+     * </ul>
+     */
+    public void timeShiftSetPlaybackRate(float rate, int audioMode) {
+        if (mSession != null) {
+            mSession.timeShiftSetPlaybackRate(rate, audioMode);
+        }
+    }
+
+    /**
+     * Sets the callback to be invoked when the time shift position is changed.
+     *
+     * @param callback The callback to receive time shift position changes. A value of {@code null}
+     *            removes the existing callback.
+     */
+    public void setTimeShiftPositionCallback(TimeShiftPositionCallback callback) {
+        mTimeShiftPositionCallback = callback;
+        ensurePositionTracking();
+    }
+
+    private void ensurePositionTracking() {
+        if (mSession == null) {
+            return;
+        }
+        mSession.timeShiftEnablePositionTracking(mTimeShiftPositionCallback != null);
+    }
+
+    /**
      * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle)
      * TvInputService.Session.appPrivateCommand()} on the current TvView.
      *
@@ -729,6 +794,38 @@
     }
 
     /**
+     * Callback used to receive time shift position changes.
+     */
+    public abstract static class TimeShiftPositionCallback {
+
+        /**
+         * This is called when the start playback position is changed.
+         * <p>
+         * The start playback position of the time shifted program can be adjusted by the TV input
+         * when it cannot retain the whole recorded program due to some reason (e.g. limitation on
+         * storage space). The application should not allow the user to seek to a position earlier
+         * than the start position.
+         * </p>
+         *
+         * @param inputId The ID of the TV input bound to this view.
+         * @param timeMs The start playback position of the time shifted program, in milliseconds
+         *            since the epoch.
+         */
+        public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
+        }
+
+        /**
+         * This is called when the current playback position is changed.
+         *
+         * @param inputId The ID of the TV input bound to this view.
+         * @param timeMs The current playback position of the time shifted program, in milliseconds
+         *            since the epoch.
+         */
+        public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
+        }
+    }
+
+    /**
      * Callback used to receive various status updates on the {@link TvView}.
      */
     public abstract static class TvInputCallback {
@@ -811,6 +908,7 @@
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_TUNING}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL}
          * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_BUFFERING}
+         * <li>{@link TvInputManager#VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY}
          * </ul>
          */
         public void onVideoUnavailable(String inputId, int reason) {
@@ -838,6 +936,7 @@
         /**
          * This is invoked when a custom event from the bound TV input is sent to this view.
          *
+         * @param inputId The ID of the TV input bound to this view.
          * @param eventType The type of the event.
          * @param eventArgs Optional arguments of the event.
          * @hide
@@ -845,6 +944,20 @@
         @SystemApi
         public void onEvent(String inputId, String eventType, Bundle eventArgs) {
         }
+
+        /**
+         * This is called when the time shift status is changed.
+         *
+         * @param inputId The ID of the TV input bound to this view.
+         * @param status The current time shift status. Should be one of the followings.
+         * <ul>
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNSUPPORTED}
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_UNAVAILABLE}
+         * <li>{@link TvInputManager#TIME_SHIFT_STATUS_AVAILABLE}
+         * </ul>
+         */
+        public void onTimeShiftStatusChanged(String inputId, int status) {
+        }
     }
 
     /**
@@ -918,6 +1031,7 @@
                     mAppPrivateCommandAction = null;
                     mAppPrivateCommandData = null;
                 }
+                ensurePositionTracking();
             } else {
                 mSessionCallback = null;
                 if (mCallback != null) {
@@ -1087,5 +1201,47 @@
                 mCallback.onEvent(mInputId, eventType, eventArgs);
             }
         }
+
+        @Override
+        public void onTimeShiftStatusChanged(Session session, int status) {
+            if (DEBUG) {
+                Log.d(TAG, "onTimeShiftStatusChanged()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onTimeShiftStatusChanged - session not created");
+                return;
+            }
+            if (mCallback != null) {
+                mCallback.onTimeShiftStatusChanged(mInputId, status);
+            }
+        }
+
+        @Override
+        public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
+            if (DEBUG) {
+                Log.d(TAG, "onTimeShiftStartPositionChanged()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onTimeShiftStartPositionChanged - session not created");
+                return;
+            }
+            if (mTimeShiftPositionCallback != null) {
+                mTimeShiftPositionCallback.onTimeShiftStartPositionChanged(mInputId, timeMs);
+            }
+        }
+
+        @Override
+        public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
+            if (DEBUG) {
+                Log.d(TAG, "onTimeShiftCurrentPositionChanged()");
+            }
+            if (this != mSessionCallback) {
+                Log.w(TAG, "onTimeShiftCurrentPositionChanged - session not created");
+                return;
+            }
+            if (mTimeShiftPositionCallback != null) {
+                mTimeShiftPositionCallback.onTimeShiftCurrentPositionChanged(mInputId, timeMs);
+            }
+        }
     }
 }
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index 7b8102b..3641ff5 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -38,7 +38,7 @@
     public MtpStorage(StorageVolume volume, Context context) {
         mStorageId = volume.getStorageId();
         mPath = volume.getPath();
-        mDescription = context.getResources().getString(volume.getDescriptionId());
+        mDescription = volume.getDescription(context);
         mReserveSpace = volume.getMtpReserveSpace() * 1024L * 1024L;
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index dae57a8..5b177e5 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -10,11 +10,12 @@
     android_media_MediaDrm.cpp \
     android_media_MediaExtractor.cpp \
     android_media_MediaHTTPConnection.cpp \
+    android_media_MediaMetadataRetriever.cpp \
     android_media_MediaMuxer.cpp \
     android_media_MediaPlayer.cpp \
     android_media_MediaRecorder.cpp \
     android_media_MediaScanner.cpp \
-    android_media_MediaMetadataRetriever.cpp \
+    android_media_MediaSync.cpp \
     android_media_ResampleInputStream.cpp \
     android_media_MediaProfiles.cpp \
     android_media_AmrInputStream.cpp \
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 708c083..043e20b 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -24,6 +24,7 @@
 #include <cstdio>
 
 #include <gui/CpuConsumer.h>
+#include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 #include <camera3.h>
 
@@ -39,7 +40,7 @@
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
 #define ANDROID_MEDIA_IMAGEREADER_CTX_JNI_ID       "mNativeContext"
-#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mLockedBuffer"
+#define ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID   "mNativeBuffer"
 #define ANDROID_MEDIA_SURFACEIMAGE_TS_JNI_ID       "mTimestamp"
 
 // ----------------------------------------------------------------------------
@@ -62,7 +63,7 @@
 } gImageReaderClassInfo;
 
 static struct {
-    jfieldID mLockedBuffer;
+    jfieldID mNativeBuffer;
     jfieldID mTimestamp;
 } gSurfaceImageClassInfo;
 
@@ -73,7 +74,7 @@
 
 // ----------------------------------------------------------------------------
 
-class JNIImageReaderContext : public CpuConsumer::FrameAvailableListener
+class JNIImageReaderContext : public ConsumerBase::FrameAvailableListener
 {
 public:
     JNIImageReaderContext(JNIEnv* env, jobject weakThiz, jclass clazz, int maxImages);
@@ -83,12 +84,19 @@
     virtual void onFrameAvailable(const BufferItem& item);
 
     CpuConsumer::LockedBuffer* getLockedBuffer();
-
     void returnLockedBuffer(CpuConsumer::LockedBuffer* buffer);
 
+    BufferItem* getOpaqueBuffer();
+    void returnOpaqueBuffer(BufferItem* buffer);
+
     void setCpuConsumer(const sp<CpuConsumer>& consumer) { mConsumer = consumer; }
     CpuConsumer* getCpuConsumer() { return mConsumer.get(); }
 
+    void setOpaqueConsumer(const sp<BufferItemConsumer>& consumer) { mOpaqueConsumer = consumer; }
+    BufferItemConsumer* getOpaqueConsumer() { return mOpaqueConsumer.get(); }
+    // This is the only opaque format exposed in the ImageFormat public API.
+    bool isOpaque() { return mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; }
+
     void setProducer(const sp<IGraphicBufferProducer>& producer) { mProducer = producer; }
     IGraphicBufferProducer* getProducer() { return mProducer.get(); }
 
@@ -109,7 +117,9 @@
     static void detachJNI();
 
     List<CpuConsumer::LockedBuffer*> mBuffers;
+    List<BufferItem*> mOpaqueBuffers;
     sp<CpuConsumer> mConsumer;
+    sp<BufferItemConsumer> mOpaqueConsumer;
     sp<IGraphicBufferProducer> mProducer;
     jobject mWeakThiz;
     jclass mClazz;
@@ -125,7 +135,9 @@
     mClazz((jclass)env->NewGlobalRef(clazz)) {
     for (int i = 0; i < maxImages; i++) {
         CpuConsumer::LockedBuffer *buffer = new CpuConsumer::LockedBuffer;
+        BufferItem* opaqueBuffer = new BufferItem;
         mBuffers.push_back(buffer);
+        mOpaqueBuffers.push_back(opaqueBuffer);
     }
 }
 
@@ -169,6 +181,21 @@
     mBuffers.push_back(buffer);
 }
 
+BufferItem* JNIImageReaderContext::getOpaqueBuffer() {
+    if (mOpaqueBuffers.empty()) {
+        return NULL;
+    }
+    // Return an opaque buffer pointer and remove it from the list
+    List<BufferItem*>::iterator it = mOpaqueBuffers.begin();
+    BufferItem* buffer = *it;
+    mOpaqueBuffers.erase(it);
+    return buffer;
+}
+
+void JNIImageReaderContext::returnOpaqueBuffer(BufferItem* buffer) {
+    mOpaqueBuffers.push_back(buffer);
+}
+
 JNIImageReaderContext::~JNIImageReaderContext() {
     bool needsDetach = false;
     JNIEnv* env = getJNIEnv(&needsDetach);
@@ -187,8 +214,20 @@
             it != mBuffers.end(); it++) {
         delete *it;
     }
+
+    // Delete opaque buffers
+    for (List<BufferItem *>::iterator it = mOpaqueBuffers.begin();
+            it != mOpaqueBuffers.end(); it++) {
+        delete *it;
+    }
+
     mBuffers.clear();
-    mConsumer.clear();
+    if (mConsumer != 0) {
+        mConsumer.clear();
+    }
+    if (mOpaqueConsumer != 0) {
+        mOpaqueConsumer.clear();
+    }
 }
 
 void JNIImageReaderContext::onFrameAvailable(const BufferItem& /*item*/)
@@ -210,6 +249,11 @@
 
 extern "C" {
 
+static bool isFormatOpaque(int format) {
+    // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
+    return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+}
+
 static JNIImageReaderContext* ImageReader_getContext(JNIEnv* env, jobject thiz)
 {
     JNIImageReaderContext *ctx;
@@ -226,6 +270,13 @@
         jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
         return NULL;
     }
+
+    if (ctx->isOpaque()) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Opaque ImageReader doesn't support this method");
+        return NULL;
+    }
+
     return ctx->getCpuConsumer();
 }
 
@@ -237,6 +288,7 @@
         jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
         return NULL;
     }
+
     return ctx->getProducer();
 }
 
@@ -258,13 +310,19 @@
 static CpuConsumer::LockedBuffer* Image_getLockedBuffer(JNIEnv* env, jobject image)
 {
     return reinterpret_cast<CpuConsumer::LockedBuffer*>(
-            env->GetLongField(image, gSurfaceImageClassInfo.mLockedBuffer));
+            env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
 }
 
 static void Image_setBuffer(JNIEnv* env, jobject thiz,
         const CpuConsumer::LockedBuffer* buffer)
 {
-    env->SetLongField(thiz, gSurfaceImageClassInfo.mLockedBuffer, reinterpret_cast<jlong>(buffer));
+    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
+}
+
+static void Image_setOpaqueBuffer(JNIEnv* env, jobject thiz,
+        const BufferItem* buffer)
+{
+    env->SetLongField(thiz, gSurfaceImageClassInfo.mNativeBuffer, reinterpret_cast<jlong>(buffer));
 }
 
 static uint32_t Image_getJpegSize(CpuConsumer::LockedBuffer* buffer, bool usingRGBAOverride)
@@ -633,6 +691,52 @@
     return buffer->height;
 }
 
+// --------------------------Methods for opaque Image and ImageReader----------
+
+static BufferItemConsumer* ImageReader_getOpaqueConsumer(JNIEnv* env, jobject thiz)
+{
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* const ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
+        return NULL;
+    }
+
+    if (!ctx->isOpaque()) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Non-opaque ImageReader doesn't support this method");
+    }
+
+    return ctx->getOpaqueConsumer();
+}
+
+static BufferItem* Image_getOpaqueBuffer(JNIEnv* env, jobject image)
+{
+    return reinterpret_cast<BufferItem*>(
+            env->GetLongField(image, gSurfaceImageClassInfo.mNativeBuffer));
+}
+
+static int Image_getOpaqueBufferWidth(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
+
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getWidth();
+    }
+    return buffer->mGraphicBuffer->getWidth();
+}
+
+static int Image_getOpaqueBufferHeight(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
+
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getHeight();
+    }
+
+    return buffer->mGraphicBuffer->getHeight();
+}
+
+
+
 // ----------------------------------------------------------------------------
 
 static void ImageReader_classInit(JNIEnv* env, jclass clazz)
@@ -642,9 +746,9 @@
     jclass imageClazz = env->FindClass("android/media/ImageReader$SurfaceImage");
     LOG_ALWAYS_FATAL_IF(imageClazz == NULL,
                         "can't find android/graphics/ImageReader$SurfaceImage");
-    gSurfaceImageClassInfo.mLockedBuffer = env->GetFieldID(
+    gSurfaceImageClassInfo.mNativeBuffer = env->GetFieldID(
             imageClazz, ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID, "J");
-    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mLockedBuffer == NULL,
+    LOG_ALWAYS_FATAL_IF(gSurfaceImageClassInfo.mNativeBuffer == NULL,
                         "can't find android/graphics/ImageReader.%s",
                         ANDROID_MEDIA_SURFACEIMAGE_BUFFER_JNI_ID);
 
@@ -691,24 +795,42 @@
     nativeDataspace = android_view_Surface_mapPublicFormatToHalDataspace(
         publicFormat);
 
-    sp<IGraphicBufferProducer> gbProducer;
-    sp<IGraphicBufferConsumer> gbConsumer;
-    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
-    sp<CpuConsumer> consumer = new CpuConsumer(gbConsumer, maxImages,
-                                               /*controlledByApp*/true);
-    // TODO: throw dvm exOutOfMemoryError?
-    if (consumer == NULL) {
-        jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
-        return;
-    }
-
     jclass clazz = env->GetObjectClass(thiz);
     if (clazz == NULL) {
         jniThrowRuntimeException(env, "Can't find android/graphics/ImageReader");
         return;
     }
     sp<JNIImageReaderContext> ctx(new JNIImageReaderContext(env, weakThiz, clazz, maxImages));
-    ctx->setCpuConsumer(consumer);
+
+    sp<IGraphicBufferProducer> gbProducer;
+    sp<IGraphicBufferConsumer> gbConsumer;
+    BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
+    sp<ConsumerBase> consumer;
+    sp<CpuConsumer> cpuConsumer;
+    sp<BufferItemConsumer> opaqueConsumer;
+    if (isFormatOpaque(nativeFormat)) {
+        // Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
+        // encoding. The only possibility will be ZSL output.
+        opaqueConsumer =
+                new BufferItemConsumer(gbConsumer, GRALLOC_USAGE_SW_READ_NEVER, maxImages,
+                        /*controlledByApp*/true);
+        if (opaqueConsumer == NULL) {
+            jniThrowRuntimeException(env, "Failed to allocate native opaque consumer");
+            return;
+        }
+        ctx->setOpaqueConsumer(opaqueConsumer);
+        consumer = opaqueConsumer;
+    } else {
+        cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
+        // TODO: throw dvm exOutOfMemoryError?
+        if (cpuConsumer == NULL) {
+            jniThrowRuntimeException(env, "Failed to allocate native CpuConsumer");
+            return;
+        }
+        ctx->setCpuConsumer(cpuConsumer);
+        consumer = cpuConsumer;
+    }
+
     ctx->setProducer(gbProducer);
     consumer->setFrameAvailableListener(ctx);
     ImageReader_setNativeContext(env, thiz, ctx);
@@ -718,23 +840,42 @@
     ctx->setBufferHeight(height);
 
     // Set the width/height/format/dataspace to the CpuConsumer
-    res = consumer->setDefaultBufferSize(width, height);
-    if (res != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                          "Failed to set CpuConsumer buffer size");
-        return;
+    // TODO: below code can be simplified once b/19977701 is fixed.
+    if (isFormatOpaque(nativeFormat)) {
+        res = opaqueConsumer->setDefaultBufferSize(width, height);
+        if (res != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                              "Failed to set opaque consumer buffer size");
+            return;
+        }
+        res = opaqueConsumer->setDefaultBufferFormat(nativeFormat);
+        if (res != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                              "Failed to set opaque consumer buffer format");
+        }
+        res = opaqueConsumer->setDefaultBufferDataSpace(nativeDataspace);
+        if (res != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                              "Failed to set opaque consumer buffer dataSpace");
+        }
+    } else {
+        res = cpuConsumer->setDefaultBufferSize(width, height);
+        if (res != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                              "Failed to set CpuConsumer buffer size");
+            return;
+        }
+        res = cpuConsumer->setDefaultBufferFormat(nativeFormat);
+        if (res != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                              "Failed to set CpuConsumer buffer format");
+        }
+        res = cpuConsumer->setDefaultBufferDataSpace(nativeDataspace);
+        if (res != OK) {
+            jniThrowException(env, "java/lang/IllegalStateException",
+                              "Failed to set CpuConsumer buffer dataSpace");
+        }
     }
-    res = consumer->setDefaultBufferFormat(nativeFormat);
-    if (res != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                          "Failed to set CpuConsumer buffer format");
-    }
-    res = consumer->setDefaultBufferDataSpace(nativeDataspace);
-    if (res != OK) {
-        jniThrowException(env, "java/lang/IllegalStateException",
-                          "Failed to set CpuConsumer buffer dataSpace");
-    }
-
 }
 
 static void ImageReader_close(JNIEnv* env, jobject thiz)
@@ -747,7 +888,13 @@
         return;
     }
 
-    CpuConsumer* consumer = ImageReader_getCpuConsumer(env, thiz);
+    ConsumerBase* consumer = NULL;
+    if (ctx->isOpaque()) {
+        consumer = ImageReader_getOpaqueConsumer(env, thiz);
+    } else {
+        consumer = ImageReader_getCpuConsumer(env, thiz);
+    }
+
     if (consumer != NULL) {
         consumer->abandon();
         consumer->setFrameAvailableListener(NULL);
@@ -764,27 +911,66 @@
         return;
     }
 
-    CpuConsumer* consumer = ctx->getCpuConsumer();
-    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
-    if (!buffer) {
-        ALOGW("Image already released!!!");
-        return;
+    if (ctx->isOpaque()) {
+        BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
+        BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
+        opaqueConsumer->releaseBuffer(*opaqueBuffer); // Not using fence for now.
+        Image_setOpaqueBuffer(env, image, NULL);
+        ctx->returnOpaqueBuffer(opaqueBuffer);
+        ALOGV("%s: Opaque Image has been released", __FUNCTION__);
+    } else {
+        CpuConsumer* consumer = ctx->getCpuConsumer();
+        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
+        if (!buffer) {
+            ALOGW("Image already released!!!");
+            return;
+        }
+        consumer->unlockBuffer(*buffer);
+        Image_setBuffer(env, image, NULL);
+        ctx->returnLockedBuffer(buffer);
+        ALOGV("%s: Image (format: 0x%x) has been released", __FUNCTION__, ctx->getBufferFormat());
     }
-    consumer->unlockBuffer(*buffer);
-    Image_setBuffer(env, image, NULL);
-    ctx->returnLockedBuffer(buffer);
 }
 
-static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz,
-                                             jobject image)
-{
+static jint ImageReader_opaqueImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
     ALOGV("%s:", __FUNCTION__);
-    JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
-    if (ctx == NULL) {
+    if (ctx == NULL || !ctx->isOpaque()) {
         jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
         return -1;
     }
 
+    BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
+    BufferItem* buffer = ctx->getOpaqueBuffer();
+    if (buffer == NULL) {
+        ALOGW("Unable to acquire a buffer item, very likely client tried to acquire more than"
+            " maxImages buffers");
+        return ACQUIRE_MAX_IMAGES;
+    }
+
+    status_t res = opaqueConsumer->acquireBuffer(buffer, 0);
+    if (res != OK) {
+        ctx->returnOpaqueBuffer(buffer);
+        if (res == INVALID_OPERATION) {
+            // Max number of images were already acquired.
+            ALOGE("%s: Max number of buffers allowed are already acquired : %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return ACQUIRE_MAX_IMAGES;
+        } else {
+            ALOGE("%s: Acquire image failed with error: %s (%d)",
+                    __FUNCTION__, strerror(-res), res);
+            return ACQUIRE_NO_BUFFERS;
+        }
+    }
+
+    // Set SurfaceImage instance member variables
+    Image_setOpaqueBuffer(env, image, buffer);
+    env->SetLongField(image, gSurfaceImageClassInfo.mTimestamp,
+            static_cast<jlong>(buffer->mTimestamp));
+
+    return ACQUIRE_SUCCESS;
+}
+
+static jint ImageReader_lockedImageSetup(JNIEnv* env, JNIImageReaderContext* ctx, jobject image) {
     CpuConsumer* consumer = ctx->getCpuConsumer();
     CpuConsumer::LockedBuffer* buffer = ctx->getLockedBuffer();
     if (buffer == NULL) {
@@ -877,23 +1063,55 @@
     return ACQUIRE_SUCCESS;
 }
 
-static void ImageReader_detachImage(JNIEnv* env, jobject thiz, jobject image) {
+static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, jobject image) {
+    ALOGV("%s:", __FUNCTION__);
+    JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
+    if (ctx == NULL) {
+        jniThrowRuntimeException(env, "ImageReaderContext is not initialized");
+        return -1;
+    }
+
+    if (ctx->isOpaque()) {
+        return ImageReader_opaqueImageSetup(env, ctx, image);
+    } else {
+        return ImageReader_lockedImageSetup(env, ctx, image);
+    }
+}
+
+static jint ImageReader_detachImage(JNIEnv* env, jobject thiz, jobject image) {
     ALOGV("%s:", __FUNCTION__);
     JNIImageReaderContext* ctx = ImageReader_getContext(env, thiz);
     if (ctx == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", "ImageReader was already closed");
-        return;
+        return -1;
     }
 
-    // CpuConsumer* consumer = ctx->getCpuConsumer();
-    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, image);
-    if (!buffer) {
-        ALOGW("Image already released!!!");
-        return;
+    status_t res = OK;
+    if (!ctx->isOpaque()) {
+        // TODO: Non-Opaque format detach is not implemented yet.
+        jniThrowRuntimeException(env,
+                "nativeDetachImage is not implemented yet for non-opaque format !!!");
+        return -1;
     }
 
-    // TODO: need implement
-    jniThrowRuntimeException(env, "nativeDetachImage is not implemented yet!!!");
+    BufferItemConsumer* opaqueConsumer = ctx->getOpaqueConsumer();
+    BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, image);
+    if (!opaqueBuffer) {
+        ALOGE(
+                "Opaque Image already released and can not be detached from ImageReader!!!");
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Opaque Image detach from ImageReader failed: buffer was already released");
+        return -1;
+    }
+
+    res = opaqueConsumer->detachBuffer(opaqueBuffer->mSlot);
+    if (res != OK) {
+        ALOGE("Opaque Image detach failed: %s (%d)!!!", strerror(-res), res);
+        jniThrowRuntimeException(env,
+                "nativeDetachImage failed for opaque image!!!");
+        return res;
+    }
+    return OK;
 }
 
 static jobject ImageReader_getSurface(JNIEnv* env, jobject thiz)
@@ -914,8 +1132,15 @@
 {
     int rowStride, pixelStride;
     PublicFormat publicReaderFormat = static_cast<PublicFormat>(readerFormat);
+    int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
+        publicReaderFormat);
 
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
+    if (isFormatOpaque(halReaderFormat)) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Opaque images from Opaque ImageReader do not have any planes");
+        return NULL;
+    }
 
     CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
 
@@ -924,9 +1149,6 @@
         jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
     }
 
-    int halReaderFormat = android_view_Surface_mapPublicFormatToHalFormat(
-        publicReaderFormat);
-
     rowStride = Image_imageGetRowStride(env, buffer, idx, halReaderFormat);
     pixelStride = Image_imageGetPixelStride(env, buffer, idx, halReaderFormat);
 
@@ -942,18 +1164,23 @@
     uint32_t size = 0;
     jobject byteBuffer;
     PublicFormat readerPublicFormat = static_cast<PublicFormat>(readerFormat);
+    int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
+            readerPublicFormat);
 
     ALOGV("%s: buffer index: %d", __FUNCTION__, idx);
 
+    if (isFormatOpaque(readerHalFormat)) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Opaque images from Opaque ImageReader do not have any plane");
+        return NULL;
+    }
+
     CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
 
     if (buffer == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", "Image was released");
     }
 
-    int readerHalFormat = android_view_Surface_mapPublicFormatToHalFormat(
-            readerPublicFormat);
-
     // Create byteBuffer from native buffer
     Image_getLockedBufferInfo(env, buffer, idx, &base, &size, readerHalFormat);
 
@@ -973,19 +1200,28 @@
     return byteBuffer;
 }
 
-static jint Image_getWidth(JNIEnv* env, jobject thiz)
+static jint Image_getWidth(JNIEnv* env, jobject thiz, jint format)
 {
-    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
-    return Image_getBufferWidth(buffer);
+    if (isFormatOpaque(format)) {
+        BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
+        return Image_getOpaqueBufferWidth(opaqueBuffer);
+    } else {
+        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+        return Image_getBufferWidth(buffer);
+    }
 }
 
-static jint Image_getHeight(JNIEnv* env, jobject thiz)
+static jint Image_getHeight(JNIEnv* env, jobject thiz, jint format)
 {
-    CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
-    return Image_getBufferHeight(buffer);
+    if (isFormatOpaque(format)) {
+        BufferItem* opaqueBuffer = Image_getOpaqueBuffer(env, thiz);
+        return Image_getOpaqueBufferHeight(opaqueBuffer);
+    } else {
+        CpuConsumer::LockedBuffer* buffer = Image_getLockedBuffer(env, thiz);
+        return Image_getBufferHeight(buffer);
+    }
 }
 
-
 } // extern "C"
 
 // ----------------------------------------------------------------------------
@@ -997,15 +1233,15 @@
     {"nativeReleaseImage",     "(Landroid/media/Image;)V",   (void*)ImageReader_imageRelease },
     {"nativeImageSetup",       "(Landroid/media/Image;)I",   (void*)ImageReader_imageSetup },
     {"nativeGetSurface",       "()Landroid/view/Surface;",   (void*)ImageReader_getSurface },
-    {"nativeDetachImage",      "(Landroid/media/Image;)V",   (void*)ImageReader_detachImage },
+    {"nativeDetachImage",      "(Landroid/media/Image;)I",   (void*)ImageReader_detachImage },
 };
 
 static JNINativeMethod gImageMethods[] = {
     {"nativeImageGetBuffer",   "(II)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
     {"nativeCreatePlane",      "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
                                                               (void*)Image_createSurfacePlane },
-    {"nativeGetWidth",         "()I",                         (void*)Image_getWidth },
-    {"nativeGetHeight",        "()I",                         (void*)Image_getHeight },
+    {"nativeGetWidth",         "(I)I",                         (void*)Image_getWidth },
+    {"nativeGetHeight",        "(I)I",                         (void*)Image_getHeight },
 };
 
 int register_android_media_ImageReader(JNIEnv *env) {
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index d10df3e..d2c614e 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -74,8 +74,8 @@
     // has returned a buffer and it is ready for ImageWriter to dequeue.
     virtual void onBufferReleased();
 
-    void setProducer(const sp<ANativeWindow>& producer) { mProducer = producer; }
-    ANativeWindow* getProducer() { return mProducer.get(); }
+    void setProducer(const sp<Surface>& producer) { mProducer = producer; }
+    Surface* getProducer() { return mProducer.get(); }
 
     void setBufferFormat(int format) { mFormat = format; }
     int getBufferFormat() { return mFormat; }
@@ -90,7 +90,7 @@
     static JNIEnv* getJNIEnv(bool* needsDetach);
     static void detachJNI();
 
-    sp<ANativeWindow> mProducer;
+    sp<Surface> mProducer;
     jobject mWeakThiz;
     jclass mClazz;
     int mFormat;
@@ -155,10 +155,21 @@
     bool needsDetach = false;
     JNIEnv* env = getJNIEnv(&needsDetach);
     if (env != NULL) {
+        // Detach the buffer every time when a buffer consumption is done,
+        // need let this callback give a BufferItem, then only detach if it was attached to this
+        // Writer. Do the detach unconditionally for opaque format now. see b/19977520
+        if (mFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+            sp<Fence> fence;
+            ANativeWindowBuffer* buffer;
+            ALOGV("%s: One buffer is detached", __FUNCTION__);
+            mProducer->detachNextBuffer(&buffer, &fence);
+        }
+
         env->CallStaticVoidMethod(mClazz, gImageWriterClassInfo.postEventFromNative, mWeakThiz);
     } else {
         ALOGW("onBufferReleased event will not posted");
     }
+
     if (needsDetach) {
         detachJNI();
     }
@@ -170,13 +181,13 @@
 
 // -------------------------------Private method declarations--------------
 
-static bool isWritable(int format);
 static bool isPossiblyYUV(PixelFormat format);
 static void Image_setNativeContext(JNIEnv* env, jobject thiz,
         sp<GraphicBuffer> buffer, int fenceFd);
 static void Image_getNativeContext(JNIEnv* env, jobject thiz,
         GraphicBuffer** buffer, int* fenceFd);
 static void Image_unlockIfLocked(JNIEnv* env, jobject thiz);
+static bool isFormatOpaque(int format);
 
 // --------------------------ImageWriter methods---------------------------------------
 
@@ -278,7 +289,7 @@
     env->SetIntField(thiz, gImageWriterClassInfo.mWriterFormat, reinterpret_cast<jint>(format));
 
 
-    if (isWritable(format)) {
+    if (!isFormatOpaque(format)) {
         res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
         if (res != OK) {
             ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
@@ -461,31 +472,87 @@
         return;
     }
 
+    // Clear the image native context: end of this image's lifecycle in public API.
     Image_setNativeContext(env, image, NULL, -1);
 }
 
-static void ImageWriter_attachImage(JNIEnv* env, jobject thiz, jlong nativeCtx, jobject image) {
+static jint ImageWriter_attachAndQueueImage(JNIEnv* env, jobject thiz, jlong nativeCtx,
+        jlong nativeBuffer, jint imageFormat, jlong timestampNs, jint left, jint top,
+        jint right, jint bottom) {
     ALOGV("%s", __FUNCTION__);
     JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx);
     if (ctx == NULL || thiz == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "ImageWriterContext is not initialized");
-        return;
+        return -1;
     }
 
-    sp<ANativeWindow> anw = ctx->getProducer();
+    sp<Surface> surface = ctx->getProducer();
+    status_t res = OK;
+    if (!isFormatOpaque(imageFormat)) {
+        // TODO: need implement, see b/19962027
+        jniThrowRuntimeException(env,
+                "nativeAttachImage for non-opaque image is not implement yet!!!");
+        return -1;
+    }
 
-    GraphicBuffer *buffer = NULL;
-    int fenceFd = -1;
-    Image_getNativeContext(env, image, &buffer, &fenceFd);
-    if (buffer == NULL) {
+    if (!isFormatOpaque(ctx->getBufferFormat())) {
         jniThrowException(env, "java/lang/IllegalStateException",
-                "Image is not initialized");
-        return;
+                "Trying to attach an opaque image into a non-opaque ImageWriter");
+        return -1;
     }
 
-    // TODO: need implement
-    jniThrowRuntimeException(env, "nativeAttachImage is not implement yet!!!");
+    // Image is guaranteed to be from ImageReader at this point, so it is safe to
+    // cast to BufferItem pointer.
+    BufferItem* opaqueBuffer = reinterpret_cast<BufferItem*>(nativeBuffer);
+    if (opaqueBuffer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Image is not initialized or already closed");
+        return -1;
+    }
+
+    // Step 1. Attach Image
+    res = surface->attachBuffer(opaqueBuffer->mGraphicBuffer.get());
+    if (res != OK) {
+        // TODO: handle different error case separately.
+        ALOGE("Attach image failed: %s (%d)", strerror(-res), res);
+        jniThrowRuntimeException(env, "nativeAttachImage failed!!!");
+        return res;
+    }
+    sp < ANativeWindow > anw = surface;
+
+    // Step 2. Set timestamp and crop. Note that we do not need unlock the image because
+    // it was not locked.
+    ALOGV("timestamp to be queued: %" PRId64, timestampNs);
+    res = native_window_set_buffers_timestamp(anw.get(), timestampNs);
+    if (res != OK) {
+        jniThrowRuntimeException(env, "Set timestamp failed");
+        return res;
+    }
+
+    android_native_rect_t cropRect;
+    cropRect.left = left;
+    cropRect.top = top;
+    cropRect.right = right;
+    cropRect.bottom = bottom;
+    res = native_window_set_crop(anw.get(), &cropRect);
+    if (res != OK) {
+        jniThrowRuntimeException(env, "Set crop rect failed");
+        return res;
+    }
+
+    // Step 3. Queue Image.
+    res = anw->queueBuffer(anw.get(), opaqueBuffer->mGraphicBuffer.get(), /*fenceFd*/
+            -1);
+    if (res != OK) {
+        jniThrowRuntimeException(env, "Queue input buffer failed");
+        return res;
+    }
+
+    // Do not set the image native context. Since it would overwrite the existing native context
+    // of the image that is from ImageReader, the subsequent image close will run into issues.
+
+    return res;
 }
 
 // --------------------------Image methods---------------------------------------
@@ -534,10 +601,13 @@
 
     // Is locked?
     bool isLocked = false;
-    jobject planes = env->GetObjectField(thiz, gSurfaceImageClassInfo.mPlanes);
+    jobject planes = NULL;
+    if (!isFormatOpaque(buffer->getPixelFormat())) {
+        planes = env->GetObjectField(thiz, gSurfaceImageClassInfo.mPlanes);
+    }
     isLocked = (planes != NULL);
     if (isLocked) {
-        // no need to use fence here, as we it will be consumed by either concel or queue buffer.
+        // no need to use fence here, as we it will be consumed by either cancel or queue buffer.
         status_t res = buffer->unlock();
         if (res != OK) {
             jniThrowRuntimeException(env, "unlock buffer failed");
@@ -900,7 +970,7 @@
     jobject byteBuffer;
 
     int format = Image_getFormat(env, thiz);
-    if (!isWritable(format) && numPlanes > 0) {
+    if (isFormatOpaque(format) && numPlanes > 0) {
         String8 msg;
         msg.appendFormat("Format 0x%x is opaque, thus not writable, the number of planes (%d)"
                 " must be 0", format, numPlanes);
@@ -915,6 +985,9 @@
                 " probably out of memory");
         return NULL;
     }
+    if (isFormatOpaque(format)) {
+        return surfacePlanes;
+    }
 
     // Buildup buffer info: rowStride, pixelStride and byteBuffers.
     LockedImage lockedImg = LockedImage();
@@ -943,13 +1016,9 @@
 
 // -------------------------------Private convenience methods--------------------
 
-// Check if buffer with this format is writable. Generally speaking, the opaque formats
-// like IMPLEMENTATION_DEFINED is not writable, as the actual buffer formats and layouts
-// are unknown to frameworks.
-static bool isWritable(int format) {
-    // Assume all other formats are writable.
-    return !(format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED ||
-            format == HAL_PIXEL_FORMAT_RAW_OPAQUE);
+static bool isFormatOpaque(int format) {
+    // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
+    return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
 }
 
 static bool isPossiblyYUV(PixelFormat format) {
@@ -986,8 +1055,8 @@
     {"nativeClassInit",         "()V",                        (void*)ImageWriter_classInit },
     {"nativeInit",              "(Ljava/lang/Object;Landroid/view/Surface;I)J",
                                                               (void*)ImageWriter_init },
-    {"nativeClose",              "(J)V",                       (void*)ImageWriter_close },
-    {"nativeAttachImage",       "(JLandroid/media/Image;)V",  (void*)ImageWriter_attachImage },
+    {"nativeClose",              "(J)V",                      (void*)ImageWriter_close },
+    {"nativeAttachAndQueueImage", "(JJIJIIII)I",          (void*)ImageWriter_attachAndQueueImage },
     {"nativeDequeueInputImage", "(JLandroid/media/Image;)V",  (void*)ImageWriter_dequeueImage },
     {"nativeQueueInputImage",   "(JLandroid/media/Image;JIIII)V",  (void*)ImageWriter_queueImage },
     {"cancelImage",             "(JLandroid/media/Image;)V",   (void*)ImageWriter_cancelImage },
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 16758d0..71457b7 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -669,6 +669,14 @@
             break;
         }
 
+        case MediaCodec::CB_CODEC_RELEASED:
+        {
+            if (!msg->findInt32("reason", &arg2)) {
+                arg2 = MediaCodec::REASON_UNKNOWN;
+            }
+            break;
+        }
+
         default:
             TRESPASS();
     }
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index d2216fb..a9accb02 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -140,6 +140,15 @@
     return jcrypto->mCrypto;
 }
 
+// JNI conversion utilities
+static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
+    Vector<uint8_t> vector;
+    size_t length = env->GetArrayLength(byteArray);
+    vector.insertAt((size_t)0, length);
+    env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
+    return vector;
+}
+
 }  // namespace android
 
 using namespace android;
@@ -274,6 +283,37 @@
     return result ? JNI_TRUE : JNI_FALSE;
 }
 
+static void android_media_MediaCrypto_setMediaDrmSession(
+        JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+    if (jsessionId == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    sp<ICrypto> crypto = JCrypto::GetCrypto(env, thiz);
+
+    if (crypto == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+        return;
+    }
+
+    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+    status_t err = crypto->setMediaDrmSession(sessionId);
+
+    String8 msg("setMediaDrmSession failed");
+    if (err == ERROR_DRM_SESSION_NOT_OPENED) {
+        msg += ": session not opened";
+    } else if (err == ERROR_UNSUPPORTED) {
+        msg += ": not supported by this crypto scheme";
+    } else if (err == NO_INIT) {
+        msg += ": crypto plugin not initialized";
+    } else if (err != OK) {
+        msg.appendFormat(": general failure (%d)", err);
+    }
+    jniThrowException(env, "android/media/MediaCryptoException", msg.string());
+}
+
 static JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaCrypto_release },
     { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
@@ -289,6 +329,9 @@
 
     { "requiresSecureDecoderComponent", "(Ljava/lang/String;)Z",
       (void *)android_media_MediaCrypto_requiresSecureDecoderComponent },
+
+    { "setMediaDrmSession", "([B)V",
+      (void *)android_media_MediaCrypto_setMediaDrmSession },
 };
 
 int register_android_media_Crypto(JNIEnv *env) {
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 96d7133..f8146a7 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -96,6 +96,12 @@
     jint kEventSessionReclaimed;
 } gEventTypes;
 
+struct EventWhat {
+    jint kWhatDrmEvent;
+    jint kWhatExpirationUpdate;
+    jint kWhatKeysChange;
+} gEventWhat;
+
 struct KeyTypes {
     jint kKeyTypeStreaming;
     jint kKeyTypeOffline;
@@ -186,25 +192,37 @@
 void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
                             const Parcel *obj)
 {
-    jint jeventType;
+    jint jwhat;
+    jint jeventType = 0;
 
     // translate DrmPlugin event types into their java equivalents
     switch (eventType) {
         case DrmPlugin::kDrmPluginEventProvisionRequired:
+            jwhat = gEventWhat.kWhatDrmEvent;
             jeventType = gEventTypes.kEventProvisionRequired;
             break;
         case DrmPlugin::kDrmPluginEventKeyNeeded:
+            jwhat = gEventWhat.kWhatDrmEvent;
             jeventType = gEventTypes.kEventKeyRequired;
             break;
         case DrmPlugin::kDrmPluginEventKeyExpired:
+            jwhat = gEventWhat.kWhatDrmEvent;
             jeventType = gEventTypes.kEventKeyExpired;
             break;
         case DrmPlugin::kDrmPluginEventVendorDefined:
+            jwhat = gEventWhat.kWhatDrmEvent;
             jeventType = gEventTypes.kEventVendorDefined;
             break;
         case DrmPlugin::kDrmPluginEventSessionReclaimed:
+            jwhat = gEventWhat.kWhatDrmEvent;
             jeventType = gEventTypes.kEventSessionReclaimed;
             break;
+        case DrmPlugin::kDrmPluginEventExpirationUpdate:
+            jwhat = gEventWhat.kWhatExpirationUpdate;
+            break;
+         case DrmPlugin::kDrmPluginEventKeysChange:
+            jwhat = gEventWhat.kWhatKeysChange;
+            break;
         default:
             ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
             return;
@@ -217,7 +235,7 @@
             Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
             nativeParcel->setData(obj->data(), obj->dataSize());
             env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
-                    jeventType, extra, jParcel);
+                    jwhat, jeventType, extra, jParcel);
             env->DeleteLocalRef(jParcel);
         }
     }
@@ -573,7 +591,7 @@
     FIND_CLASS(clazz, "android/media/MediaDrm");
     GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
     GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
-                         "(Ljava/lang/Object;IILjava/lang/Object;)V");
+                         "(Ljava/lang/Object;IIILjava/lang/Object;)V");
 
     jfieldID field;
     GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
@@ -587,6 +605,13 @@
     GET_STATIC_FIELD_ID(field, clazz, "EVENT_SESSION_RECLAIMED", "I");
     gEventTypes.kEventSessionReclaimed = env->GetStaticIntField(clazz, field);
 
+    GET_STATIC_FIELD_ID(field, clazz, "DRM_EVENT", "I");
+    gEventWhat.kWhatDrmEvent = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "EXPIRATION_UPDATE", "I");
+    gEventWhat.kWhatExpirationUpdate = env->GetStaticIntField(clazz, field);
+    GET_STATIC_FIELD_ID(field, clazz, "KEYS_CHANGE", "I");
+    gEventWhat.kWhatKeysChange = env->GetStaticIntField(clazz, field);
+
     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_STREAMING", "I");
     gKeyTypes.kKeyTypeStreaming = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "KEY_TYPE_OFFLINE", "I");
@@ -837,7 +862,7 @@
                 env->SetIntField(keyObj, gFields.keyRequest.requestType,
                         gKeyRequestTypes.kKeyRequestTypeRelease);
                 break;
-            case DrmPlugin::kKeyRequestType_Unknown:
+            default:
                 throwStateException(env, "DRM plugin failure: unknown key request type",
                         ERROR_DRM_UNKNOWN);
                 break;
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index b748f3a..3e41716 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -926,6 +926,7 @@
 extern int register_android_media_MediaMuxer(JNIEnv *env);
 extern int register_android_media_MediaRecorder(JNIEnv *env);
 extern int register_android_media_MediaScanner(JNIEnv *env);
+extern int register_android_media_MediaSync(JNIEnv *env);
 extern int register_android_media_ResampleInputStream(JNIEnv *env);
 extern int register_android_media_MediaProfiles(JNIEnv *env);
 extern int register_android_media_AmrInputStream(JNIEnv *env);
@@ -1009,6 +1010,11 @@
         goto bail;
     }
 
+    if (register_android_media_MediaSync(env) < 0) {
+        ALOGE("ERROR: MediaSync native registration failed");
+        goto bail;
+    }
+
     if (register_android_media_MediaExtractor(env) < 0) {
         ALOGE("ERROR: MediaCodec native registration failed");
         goto bail;
diff --git a/media/jni/android_media_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp
new file mode 100644
index 0000000..b96c733
--- /dev/null
+++ b/media/jni/android_media_MediaSync.cpp
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaSync-JNI"
+#include <utils/Log.h>
+
+#include "android_media_MediaSync.h"
+
+#include "android_media_AudioTrack.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_view_Surface.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <gui/Surface.h>
+
+#include <media/AudioTrack.h>
+#include <media/stagefright/MediaClock.h>
+#include <media/stagefright/MediaSync.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AString.h>
+
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+
+struct fields_t {
+    jfieldID context;
+    jfieldID mediaTimestampMediaTimeUsID;
+    jfieldID mediaTimestampNanoTimeID;
+    jfieldID mediaTimestampClockRateID;
+};
+
+static fields_t gFields;
+
+////////////////////////////////////////////////////////////////////////////////
+
+JMediaSync::JMediaSync() {
+    mSync = MediaSync::create();
+}
+
+JMediaSync::~JMediaSync() {
+}
+
+status_t JMediaSync::configureSurface(const sp<IGraphicBufferProducer> &bufferProducer) {
+    return mSync->configureSurface(bufferProducer);
+}
+
+status_t JMediaSync::configureAudioTrack(
+        const sp<AudioTrack> &audioTrack,
+        int32_t nativeSampleRateInHz) {
+    return mSync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+}
+
+status_t JMediaSync::createInputSurface(
+        sp<IGraphicBufferProducer>* bufferProducer) {
+    return mSync->createInputSurface(bufferProducer);
+}
+
+void JMediaSync::setPlaybackRate(float rate) {
+    mSync->setPlaybackRate(rate);
+}
+
+sp<const MediaClock> JMediaSync::getMediaClock() {
+    return mSync->getMediaClock();
+}
+
+status_t JMediaSync::updateQueuedAudioData(
+        int sizeInBytes, int64_t presentationTimeUs) {
+    return mSync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
+}
+
+}  // namespace android
+
+////////////////////////////////////////////////////////////////////////////////
+
+using namespace android;
+
+static sp<JMediaSync> setMediaSync(JNIEnv *env, jobject thiz, const sp<JMediaSync> &sync) {
+    sp<JMediaSync> old = (JMediaSync *)env->GetLongField(thiz, gFields.context);
+    if (sync != NULL) {
+        sync->incStrong(thiz);
+    }
+    if (old != NULL) {
+        old->decStrong(thiz);
+    }
+
+    env->SetLongField(thiz, gFields.context, (jlong)sync.get());
+
+    return old;
+}
+
+static sp<JMediaSync> getMediaSync(JNIEnv *env, jobject thiz) {
+    return (JMediaSync *)env->GetLongField(thiz, gFields.context);
+}
+
+static void android_media_MediaSync_release(JNIEnv *env, jobject thiz) {
+    setMediaSync(env, thiz, NULL);
+}
+
+static void throwExceptionAsNecessary(
+        JNIEnv *env, status_t err, const char *msg = NULL) {
+    switch (err) {
+        case INVALID_OPERATION:
+            jniThrowException(env, "java/lang/IllegalStateException", msg);
+            break;
+
+        case BAD_VALUE:
+            jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+            break;
+
+        default:
+            break;
+    }
+}
+
+static void android_media_MediaSync_native_configureSurface(
+        JNIEnv *env, jobject thiz, jobject jsurface) {
+    ALOGV("android_media_MediaSync_configureSurface");
+
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return;
+    }
+
+    sp<IGraphicBufferProducer> bufferProducer;
+    if (jsurface != NULL) {
+        sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
+        if (surface != NULL) {
+            bufferProducer = surface->getIGraphicBufferProducer();
+        } else {
+            throwExceptionAsNecessary(env, BAD_VALUE, "The surface has been released");
+            return;
+        }
+    }
+
+    status_t err = sync->configureSurface(bufferProducer);
+
+    if (err == INVALID_OPERATION) {
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, "Surface has already been configured");
+    } if (err != NO_ERROR) {
+        AString msg("Failed to connect to surface with error ");
+        msg.append(err);
+        throwExceptionAsNecessary(env, BAD_VALUE, msg.c_str());
+    }
+}
+
+static void android_media_MediaSync_native_configureAudioTrack(
+        JNIEnv *env, jobject thiz, jobject jaudioTrack, jint nativeSampleRateInHz) {
+    ALOGV("android_media_MediaSync_configureAudioTrack");
+
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return;
+    }
+
+    sp<AudioTrack> audioTrack;
+    if (jaudioTrack != NULL) {
+        audioTrack = android_media_AudioTrack_getAudioTrack(env, jaudioTrack);
+        if (audioTrack == NULL) {
+            throwExceptionAsNecessary(env, BAD_VALUE, "The audio track has been released");
+            return;
+        }
+    }
+
+    status_t err = sync->configureAudioTrack(audioTrack, nativeSampleRateInHz);
+
+    if (err == INVALID_OPERATION) {
+        throwExceptionAsNecessary(
+                env, INVALID_OPERATION, "Audio track has already been configured");
+    } if (err != NO_ERROR) {
+        AString msg("Failed to configure audio track with error ");
+        msg.append(err);
+        throwExceptionAsNecessary(env, BAD_VALUE, msg.c_str());
+    }
+}
+
+static jobject android_media_MediaSync_createInputSurface(
+        JNIEnv* env, jobject thiz) {
+    ALOGV("android_media_MediaSync_createInputSurface");
+
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return NULL;
+    }
+
+    // Tell the MediaSync that we want to use a Surface as input.
+    sp<IGraphicBufferProducer> bufferProducer;
+    status_t err = sync->createInputSurface(&bufferProducer);
+    if (err != NO_ERROR) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return NULL;
+    }
+
+    // Wrap the IGBP in a Java-language Surface.
+    return android_view_Surface_createFromIGraphicBufferProducer(env,
+            bufferProducer);
+}
+
+static void android_media_MediaSync_native_updateQueuedAudioData(
+        JNIEnv *env, jobject thiz, jint sizeInBytes, jlong presentationTimeUs) {
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return;
+    }
+
+    status_t err = sync->updateQueuedAudioData(sizeInBytes, presentationTimeUs);
+    if (err != NO_ERROR) {
+        throwExceptionAsNecessary(env, err);
+        return;
+    }
+}
+
+static jboolean android_media_MediaSync_native_getTimestamp(
+        JNIEnv *env, jobject thiz, jobject timestamp) {
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return JNI_FALSE;
+    }
+
+    sp<const MediaClock> mediaClock = sync->getMediaClock();
+    if (mediaClock == NULL) {
+        return JNI_FALSE;
+    }
+
+    int64_t nowUs = ALooper::GetNowUs();
+    int64_t mediaUs = 0;
+    if (mediaClock->getMediaTime(nowUs, &mediaUs) != OK) {
+        return JNI_FALSE;
+    }
+
+    env->SetLongField(timestamp, gFields.mediaTimestampMediaTimeUsID,
+            (jlong)mediaUs);
+    env->SetLongField(timestamp, gFields.mediaTimestampNanoTimeID,
+            (jlong)(nowUs * 1000));
+    env->SetFloatField(timestamp, gFields.mediaTimestampClockRateID,
+            (jfloat)mediaClock->getPlaybackRate());
+    return JNI_TRUE;
+}
+
+static void android_media_MediaSync_native_init(JNIEnv *env) {
+    ScopedLocalRef<jclass> clazz(env, env->FindClass("android/media/MediaSync"));
+    CHECK(clazz.get() != NULL);
+
+    gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
+    CHECK(gFields.context != NULL);
+
+    clazz.reset(env->FindClass("android/media/MediaTimestamp"));
+    CHECK(clazz.get() != NULL);
+
+    gFields.mediaTimestampMediaTimeUsID =
+        env->GetFieldID(clazz.get(), "mediaTimeUs", "J");
+    CHECK(gFields.mediaTimestampMediaTimeUsID != NULL);
+
+    gFields.mediaTimestampNanoTimeID =
+        env->GetFieldID(clazz.get(), "nanoTime", "J");
+    CHECK(gFields.mediaTimestampNanoTimeID != NULL);
+
+    gFields.mediaTimestampClockRateID =
+        env->GetFieldID(clazz.get(), "clockRate", "F");
+    CHECK(gFields.mediaTimestampClockRateID != NULL);
+}
+
+static void android_media_MediaSync_native_setup(JNIEnv *env, jobject thiz) {
+    sp<JMediaSync> sync = new JMediaSync();
+
+    setMediaSync(env, thiz, sync);
+}
+
+static void android_media_MediaSync_native_setPlaybackRate(
+        JNIEnv *env, jobject thiz, jfloat rate) {
+    sp<JMediaSync> sync = getMediaSync(env, thiz);
+    if (sync == NULL) {
+        throwExceptionAsNecessary(env, INVALID_OPERATION);
+        return;
+    }
+
+    sync->setPlaybackRate(rate);
+}
+
+static void android_media_MediaSync_native_finalize(JNIEnv *env, jobject thiz) {
+    android_media_MediaSync_release(env, thiz);
+}
+
+static JNINativeMethod gMethods[] = {
+    { "native_configureSurface",
+      "(Landroid/view/Surface;)V",
+      (void *)android_media_MediaSync_native_configureSurface },
+
+    { "native_configureAudioTrack",
+      "(Landroid/media/AudioTrack;I)V",
+      (void *)android_media_MediaSync_native_configureAudioTrack },
+
+    { "createInputSurface", "()Landroid/view/Surface;",
+      (void *)android_media_MediaSync_createInputSurface },
+
+    { "native_updateQueuedAudioData",
+      "(IJ)V",
+      (void *)android_media_MediaSync_native_updateQueuedAudioData },
+
+    { "native_getTimestamp",
+      "(Landroid/media/MediaTimestamp;)Z",
+      (void *)android_media_MediaSync_native_getTimestamp },
+
+    { "native_init", "()V", (void *)android_media_MediaSync_native_init },
+
+    { "native_setup", "()V", (void *)android_media_MediaSync_native_setup },
+
+    { "native_release", "()V", (void *)android_media_MediaSync_release },
+
+    { "native_setPlaybackRate", "(F)V", (void *)android_media_MediaSync_native_setPlaybackRate },
+
+    { "native_finalize", "()V", (void *)android_media_MediaSync_native_finalize },
+};
+
+int register_android_media_MediaSync(JNIEnv *env) {
+    return AndroidRuntime::registerNativeMethods(
+                   env, "android/media/MediaSync", gMethods, NELEM(gMethods));
+}
diff --git a/media/jni/android_media_MediaSync.h b/media/jni/android_media_MediaSync.h
new file mode 100644
index 0000000..976a456
--- /dev/null
+++ b/media/jni/android_media_MediaSync.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_MEDIASYNC_H_
+#define _ANDROID_MEDIA_MEDIASYNC_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class AudioTrack;
+struct IGraphicBufferProducer;
+struct MediaClock;
+class MediaSync;
+
+struct JMediaSync : public RefBase {
+    JMediaSync();
+
+    status_t configureSurface(const sp<IGraphicBufferProducer> &bufferProducer);
+    status_t configureAudioTrack(
+            const sp<AudioTrack> &audioTrack, int32_t nativeSampleRateInHz);
+
+    status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
+
+    status_t updateQueuedAudioData(int sizeInBytes, int64_t presentationTimeUs);
+
+    void setPlaybackRate(float rate);
+
+    sp<const MediaClock> getMediaClock();
+
+protected:
+    virtual ~JMediaSync();
+
+private:
+    sp<MediaSync> mSync;
+
+    DISALLOW_EVIL_CONSTRUCTORS(JMediaSync);
+};
+
+}  // namespace android
+
+#endif  // _ANDROID_MEDIA_MEDIASYNC_H_
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 10233f3..25c6154 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -716,7 +716,15 @@
         }
 #endif
 
-        if (!mAudioTrack.get() || mPrevSampleID != sample->sampleID()) {
+        // check if the existing track has the same sample id.
+        if (mAudioTrack != 0 && mPrevSampleID == sample->sampleID()) {
+            // the sample rate may fail to change if the audio track is a fast track.
+            if (mAudioTrack->setSampleRate(sampleRate) == NO_ERROR) {
+                newTrack = mAudioTrack;
+                ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID());
+            }
+        }
+        if (newTrack == 0) {
             // mToggle toggles each time a track is started on a given channel.
             // The toggle is concatenated with the SoundChannel address and passed to AudioTrack
             // as callback user data. This enables the detection of callbacks received from the old
@@ -746,10 +754,6 @@
             mToggle = toggle;
             mAudioTrack = newTrack;
             ALOGV("using new track %p for sample %d", newTrack.get(), sample->sampleID());
-        } else {
-            newTrack = mAudioTrack;
-            newTrack->setSampleRate(sampleRate);
-            ALOGV("reusing track %p for sample %d", mAudioTrack.get(), sample->sampleID());
         }
         newTrack->setVolume(leftVolume, rightVolume);
         newTrack->setLoop(0, frameCount, loop);
diff --git a/tests/Assistant/Android.mk b/media/packages/BluetoothMidiService/Android.mk
similarity index 68%
copy from tests/Assistant/Android.mk
copy to media/packages/BluetoothMidiService/Android.mk
index bf8cc29..2c9c3c5 100644
--- a/tests/Assistant/Android.mk
+++ b/media/packages/BluetoothMidiService/Android.mk
@@ -1,11 +1,11 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := optional
+
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_PACKAGE_NAME := Assistant
-
-LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := BluetoothMidiService
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
new file mode 100644
index 0000000..15aa581
--- /dev/null
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -0,0 +1,17 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.bluetoothmidiservice"
+        >
+
+    <uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
+    <uses-feature android:name="android.software.midi" android:required="true"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+
+    <application
+        android:label="@string/app_name">
+        <service android:name="BluetoothMidiService">
+            <intent-filter>
+                <action android:name="android.media.midi.BluetoothMidiService" />
+            </intent-filter>
+        </service>
+    </application>
+</manifest>
diff --git a/media/packages/BluetoothMidiService/res/values/strings.xml b/media/packages/BluetoothMidiService/res/values/strings.xml
new file mode 100644
index 0000000..c98e56c
--- /dev/null
+++ b/media/packages/BluetoothMidiService/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="app_name">Bluetooth MIDI Service</string>
+</resources>
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
new file mode 100644
index 0000000..8d194e5
--- /dev/null
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetoothmidiservice;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.media.midi.MidiReceiver;
+import android.media.midi.MidiManager;
+import android.media.midi.MidiDeviceServer;
+import android.media.midi.MidiDeviceInfo;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.midi.MidiEventScheduler;
+import com.android.internal.midi.MidiEventScheduler.MidiEvent;
+
+import libcore.io.IoUtils;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Class used to implement a Bluetooth MIDI device.
+ */
+public final class BluetoothMidiDevice {
+
+    private static final String TAG = "BluetoothMidiDevice";
+
+    private static final int MAX_PACKET_SIZE = 20;
+
+    //  Bluetooth MIDI Gatt service UUID
+    private static final UUID MIDI_SERVICE = UUID.fromString(
+            "03B80E5A-EDE8-4B33-A751-6CE34EC4C700");
+    // Bluetooth MIDI Gatt characteristic UUID
+    private static final UUID MIDI_CHARACTERISTIC = UUID.fromString(
+            "7772E5DB-3868-4112-A1A9-F2669D106BF3");
+    // Descriptor UUID for enabling characteristic changed notifications
+    private static final UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString(
+            "00002902-0000-1000-8000-00805f9b34fb");
+
+    private final BluetoothDevice mBluetoothDevice;
+    private final BluetoothMidiService mService;
+    private final MidiManager mMidiManager;
+    private MidiReceiver mOutputReceiver;
+    private final MidiEventScheduler mEventScheduler = new MidiEventScheduler();
+
+    private MidiDeviceServer mDeviceServer;
+    private BluetoothGatt mBluetoothGatt;
+
+    private BluetoothGattCharacteristic mCharacteristic;
+
+    // PacketReceiver for receiving formatted packets from our BluetoothPacketEncoder
+    private final PacketReceiver mPacketReceiver = new PacketReceiver();
+
+    private final BluetoothPacketEncoder mPacketEncoder
+            = new BluetoothPacketEncoder(mPacketReceiver, MAX_PACKET_SIZE);
+
+    private final BluetoothPacketDecoder mPacketDecoder
+            = new BluetoothPacketDecoder(MAX_PACKET_SIZE);
+
+    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
+        @Override
+        public void onConnectionStateChange(BluetoothGatt gatt, int status,
+                int newState) {
+            String intentAction;
+            if (newState == BluetoothProfile.STATE_CONNECTED) {
+                Log.i(TAG, "Connected to GATT server.");
+                Log.i(TAG, "Attempting to start service discovery:" +
+                        mBluetoothGatt.discoverServices());
+            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
+                Log.i(TAG, "Disconnected from GATT server.");
+                // FIXME synchronize?
+                close();
+            }
+        }
+
+        @Override
+        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+            if (status == BluetoothGatt.GATT_SUCCESS) {
+                List<BluetoothGattService> services = mBluetoothGatt.getServices();
+                for (BluetoothGattService service : services) {
+                    if (MIDI_SERVICE.equals(service.getUuid())) {
+                        Log.d(TAG, "found MIDI_SERVICE");
+                        List<BluetoothGattCharacteristic> characteristics
+                            = service.getCharacteristics();
+                        for (BluetoothGattCharacteristic characteristic : characteristics) {
+                            if (MIDI_CHARACTERISTIC.equals(characteristic.getUuid())) {
+                                Log.d(TAG, "found MIDI_CHARACTERISTIC");
+                                mCharacteristic = characteristic;
+
+                                // Specification says to read the characteristic first and then
+                                // switch to receiving notifications
+                                mBluetoothGatt.readCharacteristic(characteristic);
+                                break;
+                            }
+                        }
+                        break;
+                    }
+                }
+            } else {
+                Log.w(TAG, "onServicesDiscovered received: " + status);
+                // FIXME - report error back to client?
+            }
+        }
+
+        @Override
+        public void onCharacteristicRead(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic,
+                int status) {
+            Log.d(TAG, "onCharacteristicRead " + status);
+
+            // switch to receiving notifications after initial characteristic read
+            mBluetoothGatt.setCharacteristicNotification(characteristic, true);
+
+            BluetoothGattDescriptor descriptor = characteristic.getDescriptor(
+                    CLIENT_CHARACTERISTIC_CONFIG);
+            // FIXME null check
+            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
+            mBluetoothGatt.writeDescriptor(descriptor);
+        }
+
+        @Override
+        public void onCharacteristicWrite(BluetoothGatt gatt,
+                BluetoothGattCharacteristic characteristic,
+                int status) {
+            Log.d(TAG, "onCharacteristicWrite " + status);
+            mPacketEncoder.writeComplete();
+        }
+
+        @Override
+        public void onCharacteristicChanged(BluetoothGatt gatt,
+                                            BluetoothGattCharacteristic characteristic) {
+//            logByteArray("Received ", characteristic.getValue(), 0,
+//                    characteristic.getValue().length);
+            mPacketDecoder.decodePacket(characteristic.getValue(), mOutputReceiver);
+        }
+    };
+
+    // This receives MIDI data that has already been passed through our MidiEventScheduler
+    // and has been normalized by our MidiFramer.
+
+    private class PacketReceiver implements PacketEncoder.PacketReceiver {
+        // buffers of every possible packet size
+        private final byte[][] mWriteBuffers;
+
+        public PacketReceiver() {
+            // Create buffers of every possible packet size
+            mWriteBuffers = new byte[MAX_PACKET_SIZE + 1][];
+            for (int i = 0; i <= MAX_PACKET_SIZE; i++) {
+                mWriteBuffers[i] = new byte[i];
+            }
+        }
+
+        @Override
+        public void writePacket(byte[] buffer, int count) {
+            if (mCharacteristic == null) {
+                Log.w(TAG, "not ready to send packet yet");
+                return;
+            }
+            byte[] writeBuffer = mWriteBuffers[count];
+            System.arraycopy(buffer, 0, writeBuffer, 0, count);
+            mCharacteristic.setValue(writeBuffer);
+//            logByteArray("Sent ", mCharacteristic.getValue(), 0,
+//                    mCharacteristic.getValue().length);
+            mBluetoothGatt.writeCharacteristic(mCharacteristic);
+        }
+    }
+
+    public BluetoothMidiDevice(Context context, BluetoothDevice device,
+            BluetoothMidiService service) {
+        mBluetoothDevice = device;
+        mService = service;
+
+        mBluetoothGatt = mBluetoothDevice.connectGatt(context, false, mGattCallback);
+
+        mMidiManager = (MidiManager)context.getSystemService(Context.MIDI_SERVICE);
+
+        Bundle properties = new Bundle();
+        properties.putString(MidiDeviceInfo.PROPERTY_NAME, mBluetoothGatt.getDevice().getName());
+        properties.putParcelable(MidiDeviceInfo.PROPERTY_BLUETOOTH_DEVICE,
+                mBluetoothGatt.getDevice());
+
+        MidiReceiver[] inputPortReceivers = new MidiReceiver[1];
+        inputPortReceivers[0] = mEventScheduler.getReceiver();
+
+        mDeviceServer = mMidiManager.createDeviceServer(inputPortReceivers, 1,
+                null, null, properties, MidiDeviceInfo.TYPE_BLUETOOTH, null);
+
+        mOutputReceiver = mDeviceServer.getOutputPortReceivers()[0];
+
+        // This thread waits for outgoing messages from our MidiEventScheduler
+        // And forwards them to our MidiFramer to be prepared to send via Bluetooth.
+        new Thread("BluetoothMidiDevice " + mBluetoothDevice) {
+            @Override
+            public void run() {
+                while (true) {
+                    MidiEvent event;
+                    try {
+                        event = (MidiEvent)mEventScheduler.waitNextEvent();
+                    } catch (InterruptedException e) {
+                        // try again
+                        continue;
+                    }
+                    if (event == null) {
+                        break;
+                    }
+                    try {
+                        mPacketEncoder.sendWithTimestamp(event.data, 0, event.count,
+                                event.getTimestamp());
+                    } catch (IOException e) {
+                        Log.e(TAG, "mPacketAccumulator.sendWithTimestamp failed", e);
+                    }
+                    mEventScheduler.addEventToPool(event);
+                }
+                Log.d(TAG, "BluetoothMidiDevice thread exit");
+            }
+        }.start();
+    }
+
+    void close() {
+        mEventScheduler.close();
+        if (mDeviceServer != null) {
+            IoUtils.closeQuietly(mDeviceServer);
+            mDeviceServer = null;
+            mService.deviceClosed(mBluetoothDevice);
+        }
+        if (mBluetoothGatt != null) {
+            mBluetoothGatt.close();
+            mBluetoothGatt = null;
+        }
+    }
+
+    public IBinder getBinder() {
+        return mDeviceServer.asBinder();
+    }
+
+    private static void logByteArray(String prefix, byte[] value, int offset, int count) {
+        StringBuilder builder = new StringBuilder(prefix);
+        for (int i = offset; i < count; i++) {
+            String hex = Integer.toHexString(value[i]);
+            int length = hex.length();
+            if (length == 1) {
+                hex = "0x" + hex;
+            } else {
+                hex = hex.substring(length - 2, length);
+            }
+            builder.append(hex);
+            if (i != value.length - 1) {
+                builder.append(", ");
+            }
+        }
+        Log.d(TAG, builder.toString());
+    }
+}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
new file mode 100644
index 0000000..fbde2b4
--- /dev/null
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetoothmidiservice;
+
+import android.app.Service;
+import android.bluetooth.BluetoothDevice;
+import android.content.Intent;
+import android.media.midi.MidiManager;
+import android.os.IBinder;
+import android.util.Log;
+
+import java.util.HashMap;
+
+public class BluetoothMidiService extends Service {
+    private static final String TAG = "BluetoothMidiService";
+
+    // BluetoothMidiDevices keyed by BluetoothDevice
+    private final HashMap<BluetoothDevice,BluetoothMidiDevice> mDeviceServerMap
+            = new HashMap<BluetoothDevice,BluetoothMidiDevice>();
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (MidiManager.BLUETOOTH_MIDI_SERVICE_INTENT.equals(intent.getAction())) {
+            BluetoothDevice bluetoothDevice = (BluetoothDevice)intent.getParcelableExtra("device");
+            if (bluetoothDevice == null) {
+                Log.e(TAG, "no BluetoothDevice in onBind intent");
+                return null;
+            }
+
+            BluetoothMidiDevice device;
+            synchronized (mDeviceServerMap) {
+                device = mDeviceServerMap.get(bluetoothDevice);
+                if (device == null) {
+                    device = new BluetoothMidiDevice(this, bluetoothDevice, this);
+                }
+            }
+            return device.getBinder();
+        }
+        return null;
+    }
+
+    void deviceClosed(BluetoothDevice device) {
+        synchronized (mDeviceServerMap) {
+            mDeviceServerMap.remove(device);
+        }
+    }
+}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java
new file mode 100644
index 0000000..c5bfb5f
--- /dev/null
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketDecoder.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetoothmidiservice;
+
+import android.media.midi.MidiReceiver;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * This is an abstract base class that decodes a packet buffer and passes it to a
+ * {@link android.media.midi.MidiReceiver}
+ */
+public class BluetoothPacketDecoder extends PacketDecoder {
+
+    private static final String TAG = "BluetoothPacketDecoder";
+
+    private final byte[] mBuffer;
+
+    private final int TIMESTAMP_MASK_HIGH = 0x1F80;
+    private final int TIMESTAMP_MASK_LOW = 0x7F;
+    private final int HEADER_TIMESTAMP_MASK = 0x3F;
+
+    public BluetoothPacketDecoder(int maxPacketSize) {
+        mBuffer = new byte[maxPacketSize];
+    }
+
+    @Override
+    public void decodePacket(byte[] buffer, MidiReceiver receiver) {
+        int length = buffer.length;
+
+        // NOTE his code allows running status across packets,
+        // although the specification does not allow that.
+
+        if (length < 1) {
+            Log.e(TAG, "empty packet");
+            return;
+        }
+        byte header = buffer[0];
+        if ((header & 0xC0) != 0x80) {
+            Log.e(TAG, "packet does not start with header");
+            return;
+        }
+
+        // shift bits 0 - 5 to bits 7 - 12
+        int timestamp = (header & HEADER_TIMESTAMP_MASK) << 7;
+        boolean lastWasTimestamp = false;
+        int dataCount = 0;
+        int previousLowTimestamp = 0;
+
+        // iterate through the rest of the packet, separating MIDI data from timestamps
+        for (int i = 1; i < buffer.length; i++) {
+            byte b = buffer[i];
+
+            if ((b & 0x80) != 0 && !lastWasTimestamp) {
+                lastWasTimestamp = true;
+                int lowTimestamp = b & TIMESTAMP_MASK_LOW;
+                int newTimestamp = (timestamp & TIMESTAMP_MASK_HIGH) | lowTimestamp;
+                if (lowTimestamp < previousLowTimestamp) {
+                    newTimestamp = (newTimestamp + 0x0080) & TIMESTAMP_MASK_HIGH;
+                }
+                previousLowTimestamp = lowTimestamp;
+
+                if (newTimestamp != timestamp) {
+                    if (dataCount > 0) {
+                        // send previous message separately since it has a different timestamp
+                        try {
+                           // FIXME use sendWithTimestamp
+                            receiver.send(mBuffer, 0, dataCount);
+                        } catch (IOException e) {
+                            // ???
+                        }
+                        dataCount = 0;
+                    }
+                }
+                timestamp = newTimestamp;
+            } else {
+                lastWasTimestamp = false;
+                mBuffer[dataCount++] = b;
+            }
+        }
+
+        if (dataCount > 0) {
+            try {
+                // FIXME use sendWithTimestamp
+                receiver.send(mBuffer, 0, dataCount);
+            } catch (IOException e) {
+                // ???
+            }
+        }
+    }
+}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java
new file mode 100644
index 0000000..463edcf
--- /dev/null
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothPacketEncoder.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetoothmidiservice;
+
+import android.media.midi.MidiReceiver;
+
+import com.android.internal.midi.MidiConstants;
+import com.android.internal.midi.MidiFramer;
+
+import java.io.IOException;
+
+/**
+ * This class accumulates MIDI messages to form a MIDI packet.
+ */
+public class BluetoothPacketEncoder extends PacketEncoder {
+
+    private static final String TAG = "BluetoothPacketEncoder";
+
+    private static final long MILLISECOND_NANOS = 1000000L;
+
+    // mask for generating 13 bit timestamps
+    private static final int MILLISECOND_MASK = 0x1FFF;
+
+    private final PacketReceiver mPacketReceiver;
+
+    // buffer for accumulating messages to write
+    private final byte[] mAccumulationBuffer;
+    // number of bytes currently in mAccumulationBuffer
+    private int mAccumulatedBytes;
+    // timestamp for first message in current packet
+    private int mPacketTimestamp;
+    // current running status, or zero if none
+    private int mRunningStatus;
+
+    private boolean mWritePending;
+
+        private final Object mLock = new Object();
+
+    // This receives normalized data from mMidiFramer and accumulates it into a packet buffer
+    private final MidiReceiver mFramedDataReceiver = new MidiReceiver() {
+        @Override
+        public void onReceive(byte[] msg, int offset, int count, long timestamp)
+                throws IOException {
+
+            int milliTimestamp = (int)(timestamp / MILLISECOND_NANOS) & MILLISECOND_MASK;
+            int status = msg[0] & 0xFF;
+
+            synchronized (mLock) {
+                boolean needsTimestamp = (milliTimestamp != mPacketTimestamp);
+                int bytesNeeded = count;
+                if (needsTimestamp) bytesNeeded++;  // add one for timestamp byte
+                if (status == mRunningStatus) bytesNeeded--;    // subtract one for status byte
+
+                if (mAccumulatedBytes + bytesNeeded > mAccumulationBuffer.length) {
+                    // write out our data if there is no more room
+                    // if necessary, block until previous packet is sent
+                    flushLocked(true);
+                }
+
+                // write header if we are starting a new packet
+                if (mAccumulatedBytes == 0) {
+                    // header byte with timestamp bits 7 - 12
+                    mAccumulationBuffer[mAccumulatedBytes++] = (byte)(0x80 | (milliTimestamp >> 7));
+                    mPacketTimestamp = milliTimestamp;
+                    needsTimestamp = true;
+                }
+
+                // write new timestamp byte and status byte if necessary
+                if (needsTimestamp) {
+                    // timestamp byte with bits 0 - 6 of timestamp
+                    mAccumulationBuffer[mAccumulatedBytes++] =
+                            (byte)(0x80 | (milliTimestamp & 0x7F));
+                    mPacketTimestamp = milliTimestamp;
+                }
+
+                if (status != mRunningStatus) {
+                    mAccumulationBuffer[mAccumulatedBytes++] = (byte)status;
+                    if (MidiConstants.allowRunningStatus(status)) {
+                        mRunningStatus = status;
+                    } else if (MidiConstants.allowRunningStatus(status)) {
+                        mRunningStatus = 0;
+                    }
+                }
+
+                // now copy data bytes
+                int dataLength = count - 1;
+                System.arraycopy(msg, 1, mAccumulationBuffer, mAccumulatedBytes, dataLength);
+                // FIXME - handle long SysEx properly
+                mAccumulatedBytes += dataLength;
+
+                // write the packet if possible, but do not block
+                flushLocked(false);
+            }
+        }
+    };
+
+    // MidiFramer for normalizing incoming data
+    private final MidiFramer mMidiFramer = new MidiFramer(mFramedDataReceiver);
+
+    public BluetoothPacketEncoder(PacketReceiver packetReceiver, int maxPacketSize) {
+        mPacketReceiver = packetReceiver;
+        mAccumulationBuffer = new byte[maxPacketSize];
+    }
+
+    @Override
+    public void onReceive(byte[] msg, int offset, int count, long timestamp)
+            throws IOException {
+        // normalize the data by passing it through a MidiFramer first
+        mMidiFramer.sendWithTimestamp(msg, offset, count, timestamp);
+    }
+
+    @Override
+    public void writeComplete() {
+        synchronized (mLock) {
+            mWritePending = false;
+            flushLocked(false);
+            mLock.notify();
+        }
+    }
+
+    private void flushLocked(boolean canBlock) {
+        if (mWritePending && !canBlock) {
+            return;
+        }
+
+        while (mWritePending && mAccumulatedBytes > 0) {
+            try {
+                mLock.wait();
+            } catch (InterruptedException e) {
+                // try again
+                continue;
+            }
+        }
+
+        if (mAccumulatedBytes > 0) {
+            mPacketReceiver.writePacket(mAccumulationBuffer, mAccumulatedBytes);
+            mAccumulatedBytes = 0;
+            mPacketTimestamp = 0;
+            mRunningStatus = 0;
+            mWritePending = true;
+        }
+    }
+}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/PacketDecoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/PacketDecoder.java
new file mode 100644
index 0000000..da4b63a
--- /dev/null
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/PacketDecoder.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetoothmidiservice;
+
+import android.media.midi.MidiReceiver;
+
+/**
+ * This is an abstract base class that decodes a packet buffer and passes it to a
+ * {@link android.media.midi.MidiReceiver}
+ */
+public abstract class PacketDecoder {
+
+    /**
+     * Decodes MIDI data in a packet and passes it to a {@link android.media.midi.MidiReceiver}
+     * @param buffer the packet to decode
+     * @param receiver the {@link android.media.midi.MidiReceiver} to receive the decoded MIDI data
+     */
+    abstract public void decodePacket(byte[] buffer, MidiReceiver receiver);
+}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/PacketEncoder.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/PacketEncoder.java
new file mode 100644
index 0000000..12c8b9b
--- /dev/null
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/PacketEncoder.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetoothmidiservice;
+
+import android.media.midi.MidiReceiver;
+
+/**
+ * This is an abstract base class that encodes MIDI data into a packet buffer.
+ * PacketEncoder receives data via its {@link android.media.midi.MidiReceiver#onReceive} method
+ * and notifies its client of packets to write via the {@link PacketEncoder.PacketReceiver}
+ * interface.
+ */
+public abstract class PacketEncoder extends MidiReceiver {
+
+    public interface PacketReceiver {
+        /** Called to write an accumulated packet.
+         * @param buffer the packet buffer to write
+         * @param count the number of bytes in the packet buffer to write
+         */
+        public void writePacket(byte[] buffer, int count);
+    }
+
+    /**
+     * Called to inform PacketEncoder when the previous write is complete.
+     */
+    abstract public void writeComplete();
+}
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 165b11e..a6f7a26 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -65,5 +65,10 @@
                 <data android:scheme="package" />
             </intent-filter>
         </receiver>
+
+        <service
+            android:name=".CopyService"
+            android:exported="false">
+        </service>
     </application>
 </manifest>
diff --git a/packages/DocumentsUI/res/menu/mode_directory.xml b/packages/DocumentsUI/res/menu/mode_directory.xml
index 695060d..4b89823 100644
--- a/packages/DocumentsUI/res/menu/mode_directory.xml
+++ b/packages/DocumentsUI/res/menu/mode_directory.xml
@@ -33,4 +33,8 @@
         android:id="@+id/menu_select_all"
         android:title="@string/menu_select_all"
         android:showAsAction="never" />
+    <item
+        android:id="@+id/menu_copy"
+        android:title="@string/menu_copy"
+        android:showAsAction="never" />
 </menu>
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 19fe7a7..da87a39 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Deel"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Vee uit"</string>
     <string name="menu_select" msgid="8711270657353563424">"Kies \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Kies almal"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopieer na …"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Wys interne berging"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Wys SD-kaart"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Versteek interne berging"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Kan lêer nie oopmaak nie"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Kan sommige dokumente nie uitvee nie"</string>
     <string name="share_via" msgid="8966594246261344259">"Deel via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Kanselleer"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopieer tans lêers"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> oor"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Kopieer tans <xliff:g id="COUNT_1">%1$d</xliff:g> lêers.</item>
+      <item quantity="one">Kopieer tans <xliff:g id="COUNT_0">%1$d</xliff:g> lêer.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index 419d162..7cfb68a 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"ሁሉንም ምረጥ"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"ቅዳ ወደ…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ውስጣዊ ማከማቻ አሳይ"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ካርድ አሳይ"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ውስጣዊ ማከማቻ ደብቅ"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"ይቅር"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ፋይሎች በመገልበጥ ላይ"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ቀርቷል"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች በመቅዳት ላይ።</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች በመቅዳት ላይ።</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index 5bccdae..ea5a963 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"تحديد الكل"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"نسخ إلى…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"إظهار وحدة التخزين الداخلية"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"‏إظهار بطاقة SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"إخفاء وحدة التخزين الداخلية"</string>
@@ -55,4 +57,15 @@
     <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="cancel" msgid="6442560571259935130">"إلغاء"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"جارٍ نسخ الملفات"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"المدة المتبقية: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="zero">جارٍ نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات.</item>
+      <item quantity="two">جارٍ نسخ ملفين (<xliff:g id="COUNT_1">%1$d</xliff:g>).</item>
+      <item quantity="few">جارٍ نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> ملفات.</item>
+      <item quantity="many">جارٍ نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> ملفًا.</item>
+      <item quantity="other">جارٍ نسخ <xliff:g id="COUNT_1">%1$d</xliff:g> من الملفات.</item>
+      <item quantity="one">جارٍ نسخ ملف واحد (<xliff:g id="COUNT_0">%1$d</xliff:g>).</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 77f6855..a242c2f 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Избиране на всички"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Копиране във…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Вътр. хранилище: Показв."</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD карта: Показване"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Вътр. хранилище: Скрив."</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"Отказ"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Файловете се копират"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Оставащо време: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Копират се <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
+      <item quantity="one">Копира се <xliff:g id="COUNT_0">%1$d</xliff:g> файл.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 603cb96..c2b7fd1 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"সমস্ত নির্বাচন করুন"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"এতে অনুলিপি করুন…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"অভ্যন্তরীণ সঞ্চয়স্থান দেখান"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD কার্ড দেখান"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"অভ্যন্তরীণ সঞ্চয়স্থান লুকান"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"বাতিল করুন"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ফাইলগুলি অনুলিপি করা হচ্ছে"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> বাকি"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল অনুলিপি করা হচ্ছে৷</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>টি ফাইল অনুলিপি করা হচ্ছে৷</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index d973650..47c6ac3 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Comparteix"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Suprimeix"</string>
     <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Selecciona\'ls tots"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copia a…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra emmagatz. intern"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostra la targeta SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Amaga emmagatz. intern"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"No es pot obrir el fitxer."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"No es poden suprimir alguns documents."</string>
     <string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancel·la"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"S\'estan copiant fitxers"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Temps restant: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">S\'estan copiant <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers.</item>
+      <item quantity="one">S\'està copiant <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 36bb72f..add9331 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Sdílet"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Smazat"</string>
     <string name="menu_select" msgid="8711270657353563424">"Vyberte adresář <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Vybrat vše"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopírovat do…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobrazit inter. úložiště"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Zobrazit SD kartu"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skrýt interní úložiště"</string>
@@ -55,4 +57,13 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Soubor nelze otevřít"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Některé dokumenty nelze smazat"</string>
     <string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
+    <string name="cancel" msgid="6442560571259935130">"Zrušit"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopírování souborů"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Zbývající čas: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="few">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souborů</item>
+      <item quantity="many">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souboru</item>
+      <item quantity="other">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souborů</item>
+      <item quantity="one">Kopírování <xliff:g id="COUNT_0">%1$d</xliff:g> souboru</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index 5feb517..4d160c2 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Del"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Slet"</string>
     <string name="menu_select" msgid="8711270657353563424">"Vælg \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Vælg alle"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiér til…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis intern lagerplads"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Vis SD-kort"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skjul intern lagerplads"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Filen kan ikke åbnes"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nogle dokumenter kan ikke slettes"</string>
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Annuller"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> tilbage"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
+      <item quantity="other">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index 598862b..2183ee6 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Teilen"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Löschen"</string>
     <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" auswählen"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Alle auswählen"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopieren nach..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Int. Speicher anzeigen"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-Karte anzeigen"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Int. Speicher ausblenden"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Datei kann nicht geöffnet werden."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Einige Dokumente konnten nicht gelöscht werden."</string>
     <string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
+    <string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Dateien werden kopiert"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Noch <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien werden kopiert.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> Datei wird kopiert.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 37f99cf..8623474 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Επιλογή όλων"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Αντιγραφή σε…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Εμφ.εσωτ.χώρου αποθήκ."</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Εμφάνιση κάρτας SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Απόκρ.εσωτ.χώρου αποθήκ."</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"Ακύρωση"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Αντιγραφή αρχείων"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Απομένουν <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων.</item>
+      <item quantity="one">Αντιγραφή <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείου.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 2bd5615..7e720a1 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Share"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
     <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Select All"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Show SD card"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Hide internal storage"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
+      <item quantity="one">Copying <xliff:g id="COUNT_0">%1$d</xliff:g> file.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 2bd5615..7e720a1 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Share"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
     <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Select All"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Show SD card"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Hide internal storage"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
+      <item quantity="one">Copying <xliff:g id="COUNT_0">%1$d</xliff:g> file.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 2bd5615..7e720a1 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Share"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Delete"</string>
     <string name="menu_select" msgid="8711270657353563424">"Select \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Select All"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Show SD card"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Hide internal storage"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Cannot open file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unable to delete some documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Share via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancel"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copying files"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> left"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copying <xliff:g id="COUNT_1">%1$d</xliff:g> files.</item>
+      <item quantity="one">Copying <xliff:g id="COUNT_0">%1$d</xliff:g> file.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 4a47b73..194e19c 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
     <string name="menu_select" msgid="8711270657353563424">"Seleccionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Seleccionar todos"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copiar a…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar tarjeta SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar almacen. interno"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"No se puede abrir el archivo."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos."</string>
     <string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Faltan <xliff:g id="DURATION">%s</xliff:g>."</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
+      <item quantity="one">Copiando <xliff:g id="COUNT_0">%1$d</xliff:g> archivo</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 95cc812..f87e384 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
     <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Seleccionar todo"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copiar en…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almac. interno"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar tarjeta SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar almac. interno"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Error al abrir el archivo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"No es posible eliminar algunos documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Tiempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item>
+      <item quantity="one">Copiando <xliff:g id="COUNT_0">%1$d</xliff:g> archivo.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index c98f0b9..9b5e2a7 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Jaga"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Kustuta"</string>
     <string name="menu_select" msgid="8711270657353563424">"Kataloogi „<xliff:g id="DIRECTORY">^1</xliff:g>” valimine"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Vali kõik"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopeeri asukohta ..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Kuva sis. salvestusruum"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Kuva SD-kaart"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Peida sis. salvestusruum"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Faili ei saa avada"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Mõnda dokumenti ei õnnestu kustutada"</string>
     <string name="share_via" msgid="8966594246261344259">"Jagage teenusega"</string>
+    <string name="cancel" msgid="6442560571259935130">"Tühista"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Failide kopeerimine"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Jäänud on <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> faili kopeerimine.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> faili kopeerimine.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 1fd7b1d..075ef4b 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Partekatu"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ezabatu"</string>
     <string name="menu_select" msgid="8711270657353563424">"Hautatu \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Hautatu guztiak"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiatu hemen…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Erakutsi barneko memoria"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Erakutsi SD txartela"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ezkutatu barneko memoria"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Ezin da fitxategia ireki"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ezin izan dira dokumentu batzuk ezabatu"</string>
     <string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
+    <string name="cancel" msgid="6442560571259935130">"Utzi"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Fitxategiak kopiatzen"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Falta den denbora: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatzen.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi kopiatzen.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index 6c57211..608a369 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"انتخاب همه"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"کپی در..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"نمایش فضای ذخیره‌سازی داخلی"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"‏نمایش کارت SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"پنهان کردن فضای ذخیره‌سازی داخلی"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"لغو"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"در حال کپی کردن فایل‌ها"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی‌مانده"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">در حال کپی کردن <xliff:g id="COUNT_1">%1$d</xliff:g> فایل.</item>
+      <item quantity="other">در حال کپی کردن <xliff:g id="COUNT_1">%1$d</xliff:g> فایل.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 185be47..edcb947 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Jaa"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Poista"</string>
     <string name="menu_select" msgid="8711270657353563424">"Valitse <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Valitse kaikki"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopioi kohteeseen…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Näytä sis. tallennustila"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Näytä SD-kortti"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Piilota sis. tallennust."</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Tiedostoa ei voi avata"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Joitakin asiakirjoja ei voi poistaa"</string>
     <string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
+    <string name="cancel" msgid="6442560571259935130">"Peruuta"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopioidaan tiedostoja"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> jäljellä"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Kopioidaan <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa.</item>
+      <item quantity="one">Kopioidaan <xliff:g id="COUNT_0">%1$d</xliff:g> tiedosto.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 4e4c0ed..92f8dd6 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Partager"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
     <string name="menu_select" msgid="8711270657353563424">"Sélectionner « <xliff:g id="DIRECTORY">^1</xliff:g> »"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Tout sélectionner"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copier vers..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Afficher la carte SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Masquer mém. stock. int."</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Impossible d\'ouvrir le fichier"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents"</string>
     <string name="share_via" msgid="8966594246261344259">"Partager par"</string>
+    <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers..."</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Durée restante : <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Copier de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours.</item>
+      <item quantity="other">Copier de <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers en cours.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index b760caa..e4e5230 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Partager"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Supprimer"</string>
     <string name="menu_select" msgid="8711270657353563424">"Sélectionner \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Tout sélectionner"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copier vers…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Afficher la carte SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Masquer mém. stock. int."</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Impossible d\'ouvrir le fichier."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Impossible de supprimer certains documents."</string>
     <string name="share_via" msgid="8966594246261344259">"Partager via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Annuler"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers en cours"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Temps restant : <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours…</item>
+      <item quantity="other">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers en cours…</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index bc6ee9e..9bfdc2b 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Compartir"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
     <string name="menu_select" msgid="8711270657353563424">"Selecciona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Seleccionar todos"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copiar en…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar tarxeta SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar almacen. interno"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Non se pode abrir o ficheiro"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Non se poden eliminar algúns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copiando ficheiros"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Tempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
+      <item quantity="one">Copianto <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 88f26ed..c252cb0 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"सभी चुनें"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"इनकी कॉपी बनाएं..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आंतरिक मेमोरी दिखाएं"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD कार्ड दिखाएं"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"आंतरिक मेमोरी छिपाएं"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"अभी नहीं"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"फ़ाइलें कॉपी हो रही हैं"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शेष"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें कॉपी की जा रही हैं.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फ़ाइलें कॉपी की जा रही हैं.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 60343d2..1ab6871 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Dijeli"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
     <string name="menu_select" msgid="8711270657353563424">"Odaberi \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Odaberi sve"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiraj u…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži internu pohranu"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Pokaži SD karticu"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sakrij internu pohranu"</string>
@@ -55,4 +57,12 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Datoteku nije moguće otvoriti"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nije moguće izbrisati neke dokumente"</string>
     <string name="share_via" msgid="8966594246261344259">"Dijeli putem"</string>
+    <string name="cancel" msgid="6442560571259935130">"Odustani"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+      <item quantity="few">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+      <item quantity="other">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index a9b5a7c..b642f8f 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Megosztás"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Törlés"</string>
     <string name="menu_select" msgid="8711270657353563424">"A(z) „<xliff:g id="DIRECTORY">^1</xliff:g>” mappa kiválasztása"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Az összes kijelölése"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Másolás ide…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Belső tárhely"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-kártya megjelenítése"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Belső tárhely elrejtése"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"A fájlt nem lehet megnyitni"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Néhány dokumentumot nem lehet törölni"</string>
     <string name="share_via" msgid="8966594246261344259">"Megosztás itt:"</string>
+    <string name="cancel" msgid="6442560571259935130">"Mégse"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Fájlok másolása"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> van hátra"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fájl másolása.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> fájl másolása.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 487f5bd..6ca909b 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Ընտրել բոլորը"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Պատճենել…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ցույց տալ ներքին պահոցը"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Ցույց տալ SD քարտը"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Թաքցնել ներքին պահոցը"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"Չեղարկել"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Ֆայլերի պատճենում"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Մնացել է <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլի պատճենում:</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլի պատճենում:</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 1514fc6..8384b62 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Bagikan"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Hapus"</string>
     <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Pilih Semua"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Salin ke…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Tampilkan simpanan internal"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Tampilkan kartu SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sembunyikan simpanan internal"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Tidak dapat membuka file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat menghapus beberapa dokumen"</string>
     <string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
+    <string name="cancel" msgid="6442560571259935130">"Batal"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Menyalin file"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
+      <item quantity="one">Menyalin <xliff:g id="COUNT_0">%1$d</xliff:g> file.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index f324dad..4b3448a 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Deila"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eyða"</string>
     <string name="menu_select" msgid="8711270657353563424">"Velja „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Velja allt"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Afrita í ..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Sýna innbyggða geymslu"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Sýna SD-kort"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Fela innbyggða geymslu"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Ekki er hægt að opna skrána"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ekki er hægt að eyða einhverjum skjölum"</string>
     <string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
+    <string name="cancel" msgid="6442560571259935130">"Hætta við"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Afritar skrár"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> eftir"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Afritar <xliff:g id="COUNT_1">%1$d</xliff:g> skrá.</item>
+      <item quantity="other">Afritar <xliff:g id="COUNT_1">%1$d</xliff:g> skrár.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index a073c44..87c8f92 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Condividi"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Elimina"</string>
     <string name="menu_select" msgid="8711270657353563424">"Seleziona \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Seleziona tutti"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copia in…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra memoria interna"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostra scheda SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Nascondi memoria interna"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Impossibile aprire il file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Impossibile eliminare alcuni documenti"</string>
     <string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Annulla"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copia di file in corso"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item>
+      <item quantity="one">Copia di <xliff:g id="COUNT_0">%1$d</xliff:g> file in corso.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 6ab2880..ed387be 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"בחר הכל"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"העתק אל…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"הצג אחסון פנימי"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"‏הצג כרטיס SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"הסתר אחסון פנימי"</string>
@@ -55,4 +57,13 @@
     <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="cancel" msgid="6442560571259935130">"ביטול"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"מעתיק קבצים"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"זמן נותר: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="two">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
+      <item quantity="many">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
+      <item quantity="other">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
+      <item quantity="one">מעתיק קובץ <xliff:g id="COUNT_0">%1$d</xliff:g>.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index f57a21c..e393940 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"すべて選択"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"コピー…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"内部ストレージを表示"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SDカードを表示"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"内部ストレージを非表示"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"キャンセル"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ファイルのコピー中"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"残り<xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>個のファイルをコピーしています。</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g>個のファイルをコピーしています。</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index b1e39b8..a3fdd19 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"ყველას არჩევა"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"კოპირება…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"შიდა საცავის ჩვენება"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ბარათის ჩვენება"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"შიდა მეხსიერების დამალვა"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"გაუქმება"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"მიმდ. ფაილების კოპირება"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"დარჩა <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">მიმდინარეობს <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის კოპირება.</item>
+      <item quantity="one">მიმდინარეობს <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის კოპირება.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index c7e207c..8fb36ab 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Барлығын таңдау"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Көшіру орны…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ішкі жадты көрсету"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD картасын көрсету"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ішкі жадты жасыру"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"Бас тарту"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Файлдарды көшіру"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> қалды"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды көшіру.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды көшіру.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 3055001..618284c 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"ជ្រើសរើសទាំងអស់"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"ថតចម្លងទៅ…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"បង្ហាញឧបករណ៍ផ្ទុកខាងក្នុង"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"បង្ហាញកាតអេសឌី"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"លាក់​ឧបករណ៍​​ផ្ទុក​ខាងក្នុង"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"បោះ​បង់​"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"កំពុងថតចម្លងឯកសារ"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"នៅសល់ <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">កំពុងថតចម្លងឯកសារចំនួន <xliff:g id="COUNT_1">%1$d</xliff:g> ។</item>
+      <item quantity="one">កំពុងថតចម្លងឯកសារចំនួន <xliff:g id="COUNT_0">%1$d</xliff:g> ។</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 508f0e5..bcff2e3 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"ಎಲ್ಲವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"ಇದಕ್ಕೆ ನಕಲಿಸಿ…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯನ್ನು ತೋರಿಸು"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ಕಾಡ್‌ ಅನ್ನು ತೋರಿಸು"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯನ್ನು ಮರೆಮಾಡಿ"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"ರದ್ದುಮಾಡು"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ಉಳಿದಿದೆ"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ.</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ಫೈಲ್‌ಗಳನ್ನು ನಕಲಿಸಲಾಗುತ್ತಿದೆ.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index d6f0cbd..87ac2e7 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"모두 선택"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"복사…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"내부 저장소 표시"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD 카드 표시"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"내부 저장소 숨기기"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"취소"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"파일 복사 중"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> 남음"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">파일 <xliff:g id="COUNT_1">%1$d</xliff:g>개를 복사하는 중입니다.</item>
+      <item quantity="one">파일 <xliff:g id="COUNT_0">%1$d</xliff:g>개를 복사하는 중입니다.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index a4f718b..3ff8b2e 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Бардыгын тандоо"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Төмөнкүгө көчүрүү…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ички сактагычты көрсөтүү"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD картаны көрсөтүү"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ички эстутумду жашыруу"</string>
@@ -55,4 +57,12 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Файл ачылбады"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Кээ бир документтерди өчүрүү кыйрады"</string>
     <string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
+    <!-- no translation found for cancel (6442560571259935130) -->
+    <skip />
+    <string name="copy_notification_title" msgid="6374299806748219777">"Файлдар көчүрүлүүдө"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> калды"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлүүдө.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файл көчүрүлүүдө.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 8db69c7..3feb613 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"ເລືອກທັງຫມົດ"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"ອັດ​ສຳ​ເນົາ​ໃສ່…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ສະແດງ​ໂຕເກັບ​ຂໍ້ມູນພາຍໃນ"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"ສະແດງ SD Card"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ເຊື່ອງ​ໂຕ​ເກັບຂໍ້ມູນ​ພາຍໃນ"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"ຍົກເລີກ"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ​ໄຟ​ລ໌"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ຍັງ​ເຫຼືອ​ຢູ່"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ <xliff:g id="COUNT_1">%1$d</xliff:g> ໄຟ​ລ໌.</item>
+      <item quantity="one">ກຳ​ລັງ​ອັດ​ສຳ​ເນົາ <xliff:g id="COUNT_0">%1$d</xliff:g> ໄຟ​ລ໌.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 81412c5..659c207 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Bendrinti"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ištrinti"</string>
     <string name="menu_select" msgid="8711270657353563424">"Pasirinkti katalogą „<xliff:g id="DIRECTORY">^1</xliff:g>“"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Pasirinkti viską"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopijuoti į..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rodyti vidinę atmintį"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Rodyti SD kortelę"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Slėpti vidinę atmintį"</string>
@@ -55,4 +57,13 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Nepavyksta atidaryti failo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nepavyko ištrinti kai kurių dokumentų"</string>
     <string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
+    <string name="cancel" msgid="6442560571259935130">"Atšaukti"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopijuojami failai"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Liko: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Kopijuojamas <xliff:g id="COUNT_1">%1$d</xliff:g> failas.</item>
+      <item quantity="few">Kopijuojami <xliff:g id="COUNT_1">%1$d</xliff:g> failai.</item>
+      <item quantity="many">Kopijuojama <xliff:g id="COUNT_1">%1$d</xliff:g> failo.</item>
+      <item quantity="other">Kopijuojama <xliff:g id="COUNT_1">%1$d</xliff:g> failų.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 0cd5812..7818404 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Kopīgot"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Dzēst"</string>
     <string name="menu_select" msgid="8711270657353563424">"Atlasīt “<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Atlasīt visus"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopēt…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rādīt iekšējo atmiņu"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Rādīt SD karti"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Paslēpt iekšējo atmiņu"</string>
@@ -55,4 +57,12 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Nevar atvērt failu."</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nevar dzēst dažus dokumentus."</string>
     <string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
+    <string name="cancel" msgid="6442560571259935130">"Atcelt"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Notiek failu kopēšana"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Atlikušais laiks: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="zero">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> failu kopēšana.</item>
+      <item quantity="one">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> faila kopēšana.</item>
+      <item quantity="other">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> failu kopēšana.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index d909741..0c09849 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Избери ги сите"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Копирај во…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи внатрешна мемор."</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Прикажи СД-картичка"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Скриј внатрешна меморија"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"Откажи"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Се копираат датотеки"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Уште <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Се копира <xliff:g id="COUNT_1">%1$d</xliff:g> датотека.</item>
+      <item quantity="other">Се копираат <xliff:g id="COUNT_1">%1$d</xliff:g> датотеки.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 24f4815..45824ba 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"എല്ലാം തിരഞ്ഞെടുക്കുക"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"ഇതിൽ പകർത്തുക…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ആന്തരിക സംഭരണം കാണിക്കുക"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD കാർഡ് കാണിക്കുക"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ആന്തരിക സംഭരണം മറയ്‌ക്കുക"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"റദ്ദാക്കുക"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ഫയലുകൾ പകർത്തുന്നു"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ശേഷിക്കുന്നു"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ഫയലുകൾ പകർത്തുന്നു.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ഫയൽ പകർത്തുന്നു.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 141032d..bbb3e91 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Бүгдийг сонгох"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"...руу хуулах"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Дотоод санг харуулах"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD картыг харуулах"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Дотоод санг нуух"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"Цуцлах"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Файлуудыг хуулж байна"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> үлдсэн"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлуудыг хуулж байна.</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> файл хуулж байна.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index b59ded5..83572b0 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"सर्व निवडा"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"यावर कॉपी करा…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"अंतर्गत संचयन दर्शवा"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD कार्ड दर्शवा"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"अंतर्गत संचयन लपवा"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"रद्द करा"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"फायली कॉपी करीत आहे"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शिल्लक"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल कॉपी करीत आहे.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> फायली कॉपी करीत आहे.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 5330d92..10d4351 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Kongsi"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Padam"</string>
     <string name="menu_select" msgid="8711270657353563424">"Pilih \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Pilih Semua"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Salin ke..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Papar storan dalaman"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Papar kad SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Sembunyikan storan dlmn"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Tidak dapat membuka fail"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Tidak dapat memadam beberapa dokumen"</string>
     <string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
+    <string name="cancel" msgid="6442560571259935130">"Batal"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Menyalin fail"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> yang tinggal"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail.</item>
+      <item quantity="one">Menyalin <xliff:g id="COUNT_0">%1$d</xliff:g> fail.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 50f8363..b63ecf5 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"အားလုံးရွေးရန်"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"သို့ကူးယူရန်…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"စက်ရှိစတိုရုံ ပြပါ"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD ကဒ် ပြပါ"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"စက်ရှိစတိုရုံ ဖျောက်ထားပါ"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"ထားတော့"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ဖိုင်များကူယူနေသည်"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ကျန်ရှိသည်"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ဖိုင်များကို ကူးယူနေသည်။</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ဖိုင် ကူးယူနေသည်။</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index beee44f..0a3117a 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Del"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Slett"</string>
     <string name="menu_select" msgid="8711270657353563424">"Velg «<xliff:g id="DIRECTORY">^1</xliff:g>»"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Velg alle"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiér til …"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis den interne lagringen"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Vis SD-kortet"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skjul den interne lagringen"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Kan ikke åpne filen"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Enkelte dokumenter kunne ikke slettes"</string>
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> gjenstår"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
+      <item quantity="one">Kopierer <xliff:g id="COUNT_0">%1$d</xliff:g> fil.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 4251a7c..69dc562 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"सबै चयन गर्नुहोस्"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"प्रतिलिपि गर्नुहोस् ..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आन्तरिक भण्डारण देखाउनुहोस्"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD कार्ड देखाउनुहोस्"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"आन्तरिक भण्डारण लुकाउनुहोस्"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"रद्द गर्नुहोस्"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"फाइलहरू प्रतिलिपि गर्दै:"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g>बाँकी"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g>फाइलहरू प्रतिलिप गर्दै।</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> फाइल प्रतिलिपि गर्दै।</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 1fc7dc1..7d17c5a 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Delen"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Verwijderen"</string>
     <string name="menu_select" msgid="8711270657353563424">"<xliff:g id="DIRECTORY">^1</xliff:g> selecteren"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Alles selecteren"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiëren naar…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Interne opslag weergeven"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-kaart weergeven"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Interne opslag verbergen"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Kan bestand niet openen"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Kan bepaalde documenten niet verwijderen"</string>
     <string name="share_via" msgid="8966594246261344259">"Delen via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Annuleren"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Bestanden kopiëren"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> resterend"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> bestanden kopiëren.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> bestand kopiëren.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 5bb7f75..b87c322 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Udostępnij"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Usuń"</string>
     <string name="menu_select" msgid="8711270657353563424">"Zaznacz „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Wybierz wszystko"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiuj do…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaż pamięć wewnętrzną"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Pokaż kartę SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ukryj pamięć wewnętrzną"</string>
@@ -55,4 +57,13 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Nie można otworzyć pliku"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nie można usunąć niektórych dokumentów"</string>
     <string name="share_via" msgid="8966594246261344259">"Udostępnij przez"</string>
+    <string name="cancel" msgid="6442560571259935130">"Anuluj"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopiowanie plików"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Pozostało: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="few">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> plików.</item>
+      <item quantity="many">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> plików.</item>
+      <item quantity="other">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> pliku.</item>
+      <item quantity="one">Kopiowanie <xliff:g id="COUNT_0">%1$d</xliff:g> pliku.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index e32dfc9..62774e5 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Partilhar"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Eliminar"</string>
     <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Selecionar tudo"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copiar para…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar mem. armaz. int."</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar cartão SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar mem. armaz. int."</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o ficheiro"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Não é possível eliminar alguns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"A copiar ficheiros"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">A copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
+      <item quantity="one">A copiar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 2aaa4d2..6c65639 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Compartilhar"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Excluir"</string>
     <string name="menu_select" msgid="8711270657353563424">"Selecionar \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Selecionar tudo"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copiar para..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar armaz. interno"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Mostrar cartão SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ocultar armaz. interno"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Não é possível abrir o arquivo"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Não foi possível excluir alguns documentos"</string>
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Cancelar"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
+      <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index c5de856..2d72458 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Distribuiți"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ștergeți"</string>
     <string name="menu_select" msgid="8711270657353563424">"Selectați „<xliff:g id="DIRECTORY">^1</xliff:g>”"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Selectați-le pe toate"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Copiați în…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Afișați stocarea internă"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Afișați cardul SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ascundeți stocarea internă"</string>
@@ -55,4 +57,12 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Fișierul nu poate fi deschis"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Unele documente nu au putut fi șterse"</string>
     <string name="share_via" msgid="8966594246261344259">"Distribuiți prin"</string>
+    <string name="cancel" msgid="6442560571259935130">"Anulați"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Se copiază fișierele"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Timp rămas: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="few">Se copiază <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere.</item>
+      <item quantity="other">Se copiază <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere.</item>
+      <item quantity="one">Se copiază <xliff:g id="COUNT_0">%1$d</xliff:g> fișier.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 10de6f0..3751008 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Выбрать все"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Копировать в…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Внутренняя память"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD-карта"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Скрыть внутреннюю память"</string>
@@ -55,4 +57,13 @@
     <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="cancel" msgid="6442560571259935130">"Отмена"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Копирование файлов"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Осталось <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файл...</item>
+      <item quantity="few">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файла...</item>
+      <item quantity="many">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файлов...</item>
+      <item quantity="other">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файла...</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 26e2b1d..b32ba79 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"සියල්ල තෝරන්න"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"වෙත පිටපත් කරන්න..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"අභ්‍යන්තර ආචයනය පෙන්වන්න"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD කාඩ් පත පෙන්වන්න"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"අභ්‍යන්තර ආචයනය සඟවන්න"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"අවලංගු කරන්න"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ගොනු පිටපත් කරමින්"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g>DURATION ඉතිරියි"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් පිටපත් කරමින්.</item>
+      <item quantity="other">ගොනු <xliff:g id="COUNT_1">%1$d</xliff:g> ක් පිටපත් කරමින්.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index facaf4a..557f8db 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Zdieľať"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Odstrániť"</string>
     <string name="menu_select" msgid="8711270657353563424">"Vyberte adresár <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Vybrať všetko"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopírovať do…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobraziť interné úložisko"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Zobraziť kartu SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skryť interné úložisko"</string>
@@ -55,4 +57,13 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Súbor sa nepodarilo otvoriť"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Niektoré dokumenty sa nepodarilo odstrániť"</string>
     <string name="share_via" msgid="8966594246261344259">"Zdieľať pomocou"</string>
+    <string name="cancel" msgid="6442560571259935130">"Zrušiť"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopírovanie súborov"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Zostáva: <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="few">Kopírujú sa <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
+      <item quantity="many">Kopíruje sa <xliff:g id="COUNT_1">%1$d</xliff:g> súboru.</item>
+      <item quantity="other">Kopíruje sa <xliff:g id="COUNT_1">%1$d</xliff:g> súborov.</item>
+      <item quantity="one">Kopíruje sa <xliff:g id="COUNT_0">%1$d</xliff:g> súbor.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 865df8b..200d46d 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Skupna raba"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Izbriši"</string>
     <string name="menu_select" msgid="8711270657353563424">"Izbira mape »<xliff:g id="DIRECTORY">^1</xliff:g>«"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Izberi vse"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiranje v …"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži notranjo shrambo"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Pokaži kartico SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Skrij notranjo shrambo"</string>
@@ -55,4 +57,13 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Datoteke ni mogoče odpreti"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Nekaterih dokumentov ni mogoče izbrisati"</string>
     <string name="share_via" msgid="8966594246261344259">"Deli z drugimi prek"</string>
+    <string name="cancel" msgid="6442560571259935130">"Prekliči"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datotek"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Še <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
+      <item quantity="two">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datotek.</item>
+      <item quantity="few">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datotek.</item>
+      <item quantity="other">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datotek.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index fd20722..e3d6d3c 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Изабери све"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Копирај на..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи интерну меморију"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Прикажи SD картицу"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Сакриј интерну меморију"</string>
@@ -55,4 +57,12 @@
     <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="cancel" msgid="6442560571259935130">"Откажи"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Копирање датотека"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Још <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке.</item>
+      <item quantity="few">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке.</item>
+      <item quantity="other">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотека.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index a77b75d..fa467aa 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Dela"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Ta bort"</string>
     <string name="menu_select" msgid="8711270657353563424">"Välj <xliff:g id="DIRECTORY">^1</xliff:g>"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Markera alla"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopiera till …"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Visa internminne"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Visa SD-kort"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Dölj internminne"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Det går inte att öppna filen"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Det gick inte att ta bort vissa dokument"</string>
     <string name="share_via" msgid="8966594246261344259">"Dela via"</string>
+    <string name="cancel" msgid="6442560571259935130">"Avbryt"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kopierar filer"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> återstår"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Kopierar <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
+      <item quantity="one">Kopierar <xliff:g id="COUNT_0">%1$d</xliff:g> fil.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b46d97f..d062c7a 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Shiriki"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Futa"</string>
     <string name="menu_select" msgid="8711270657353563424">"Chagua \" <xliff:g id="DIRECTORY">^1</xliff:g> \""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Chagua Zote"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Nakili kwenda..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Onyesha hifadhi ya ndani"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Onyesha kadi ya SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ficha hifadhi ya ndani"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Haiwezi kufungua faili"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Imeshindwa kufuta baadhi ya hati"</string>
     <string name="share_via" msgid="8966594246261344259">"Shiriki kupitia"</string>
+    <string name="cancel" msgid="6442560571259935130">"Ghairi"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Inanakili faili"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Zimesalia <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Inanakili faili <xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
+      <item quantity="one">Inanakili faili <xliff:g id="COUNT_0">%1$d</xliff:g>.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 5b09b97..38c3b98 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"எல்லாவற்றையும் தேர்ந்தெடு"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"இங்கு நகலெடு…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"அகச் சேமிப்பகத்தைக் காட்டு"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD கார்டைக் காட்டு"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"அகச் சேமிப்பகத்தை மறை"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"ரத்துசெய்"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"கோப்புகளை நகலெடுத்தல்"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> மீதமுள்ளது"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> கோப்புகளை நகலெடுக்கிறது.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> கோப்பை நகலெடுக்கிறது.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index e04724a..3497d17 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"అన్నీ ఎంచుకోండి"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"ఇక్కడికి కాపీ చేయి…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"అంతర్గత నిల్వను చూపు"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD కార్డ్‌ను చూపు"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"అంతర్గత నిల్వను దాచు"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"రద్దు చేయండి"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"ఫైల్‌లు కాపీ అవుతున్నాయి"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> మిగిలి ఉంది"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ఫైల్‌లను కాపీ చేస్తోంది.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ఫైల్‌ను కాపీ చేస్తోంది.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 5410d37..8241eae 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"เลือกทั้งหมด"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"คัดลอกไปยัง…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"แสดงที่จัดเก็บภายใน"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"แสดงการ์ด SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"ซ่อนที่จัดเก็บภายใน"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"ยกเลิก"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"กำลังคัดลอกไฟล์"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"เหลือ <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">กำลังคัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+      <item quantity="one">กำลังคัดลอก <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 3defd6a..80975c9 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Ibahagi"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Tanggalin"</string>
     <string name="menu_select" msgid="8711270657353563424">"Piliin ang \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Piliin Lahat"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopyahin sa..."</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ipakita internal storage"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Ipakita ang SD card"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Itago internal storage"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Hindi mabuksan ang file"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Hindi matanggal ang ilang dokumento"</string>
     <string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
+    <string name="cancel" msgid="6442560571259935130">"Kanselahin"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Kinokopya ang mga file"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> na lang ang natitira"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Kumokopya ng <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
+      <item quantity="other">Kumokopya ng <xliff:g id="COUNT_1">%1$d</xliff:g> na file.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 9f0f846..b527c88 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Paylaş"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Sil"</string>
     <string name="menu_select" msgid="8711270657353563424">"\"<xliff:g id="DIRECTORY">^1</xliff:g>\" dizinini seç"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Tümünü Seç"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopyala…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Dahili depolamayı göster"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD kartı göster"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Dahili depolamayı gizle"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Dosya açılamıyor"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Bazı dokümanlar silinemiyor"</string>
     <string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
+    <string name="cancel" msgid="6442560571259935130">"İptal"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Dosyalar kopyalanıyor"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> kaldı"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanıyor.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosya kopyalanıyor.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 5be1947..4183941 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"Вибрати все"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Копіювати в…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Показати внутр. пам’ять"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Показати карту SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Сховати внутр. пам’ять"</string>
@@ -55,4 +57,13 @@
     <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="cancel" msgid="6442560571259935130">"Скасувати"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Копіювання файлів"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Залишилося <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
+      <item quantity="few">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлів.</item>
+      <item quantity="many">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлів.</item>
+      <item quantity="other">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 729fc7f..17efa3b 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"سبھی منتخب کریں"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"اس پر کاپی ہو رہی ہے…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"داخلی اسٹوریج دکھائیں"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"‏SD کارڈ دکھائیں"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"داخلی اسٹوریج چھپائیں"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"منسوخ کریں"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"فائلیں کاپی ہو رہی ہیں"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی ہے"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی کی جا رہی ہیں۔</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> فائل کاپی کی جا رہی ہے۔</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index db35356..76c590a 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Ulashish"</string>
     <string name="menu_delete" msgid="8138799623850614177">"O‘chirish"</string>
     <string name="menu_select" msgid="8711270657353563424">"“<xliff:g id="DIRECTORY">^1</xliff:g>” jildini tanlash"</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Barchasini tanlash"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"...ga nusxalash"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ichki xotirani ko‘rsatish"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"SD kartani ko‘rsatish"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ichki xotirani berkitish"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Fayl ochilmadi"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ba’zi hujjatlar o‘chirilmadi"</string>
     <string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
+    <string name="cancel" msgid="6442560571259935130">"Bekor qilish"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Fayllar nusxalanmoqda"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qoldi"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl nusxalanmoqda</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl nusxalanmoqda</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index e4bbfda..ee334db 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Chia sẻ"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Xóa"</string>
     <string name="menu_select" msgid="8711270657353563424">"Chọn \"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Chọn tất cả"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Sao chép vào…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Hiển thị bộ nhớ trong"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Hiển thị thẻ SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Ẩn bộ nhớ trong"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Không thể mở tệp"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Không thể xóa một số tài liệu"</string>
     <string name="share_via" msgid="8966594246261344259">"Chia sẻ qua"</string>
+    <string name="cancel" msgid="6442560571259935130">"Hủy"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Đang sao chép tệp"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"Còn <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">Đang sao chép <xliff:g id="COUNT_1">%1$d</xliff:g> tệp.</item>
+      <item quantity="one">Đang sao chép <xliff:g id="COUNT_0">%1$d</xliff:g> tệp.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index 4a44250..8e3b15b 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"全选"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"复制到…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"显示内部存储设备"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"显示SD卡"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"隐藏内部存储设备"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"取消"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"正在复制文件"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"剩余时间:<xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
+      <item quantity="one">正在复制 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件。</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index e245c12..a03658d 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"全部選取"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"複製到…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"顯示 SD 卡"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"隱藏內部儲存空間"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"取消"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"正在複製檔案"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
+      <item quantity="one">正在複製 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案。</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 464a13e..10b42de 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -30,6 +30,8 @@
     <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="menu_select_all" msgid="4320518282375109902">"全選"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"複製到…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"顯示 SD 卡"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"隱藏內部儲存空間"</string>
@@ -55,4 +57,11 @@
     <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="cancel" msgid="6442560571259935130">"取消"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"複製檔案"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
+      <item quantity="one">正在複製 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案。</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index b35da3c..dd37993 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -30,6 +30,8 @@
     <string name="menu_share" msgid="3075149983979628146">"Yabelana"</string>
     <string name="menu_delete" msgid="8138799623850614177">"Susa"</string>
     <string name="menu_select" msgid="8711270657353563424">"Khetha i-\"<xliff:g id="DIRECTORY">^1</xliff:g>\""</string>
+    <string name="menu_select_all" msgid="4320518282375109902">"Khetha konke"</string>
+    <string name="menu_copy" msgid="3612326052677229148">"Kopishela ku…"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Bonisa isitoreji sangaphakathi"</string>
     <string name="menu_advanced_show" product="default" msgid="5792182900084144261">"Bonisa ikhadi le-SD"</string>
     <string name="menu_advanced_hide" product="nosdcard" msgid="4218809952721972589">"Fihla isitoreji sangaphakathi"</string>
@@ -55,4 +57,11 @@
     <string name="toast_no_application" msgid="1339885974067891667">"Ayikwazi ukuvula ifayela"</string>
     <string name="toast_failed_delete" msgid="2180678019407244069">"Ayikwazi ukususa amanye amadokhumenti"</string>
     <string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
+    <string name="cancel" msgid="6442560571259935130">"Khansela"</string>
+    <string name="copy_notification_title" msgid="6374299806748219777">"Ikopisha amafayela"</string>
+    <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> okusele"</string>
+    <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
+      <item quantity="one">Ikopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
+      <item quantity="other">Ikopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
+    </plurals>
 </resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 4ad337d..3ca239a 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -48,6 +48,8 @@
     <string name="menu_select">Select \"<xliff:g id="directory" example="My Directory">^1</xliff:g>\"</string>
     <!-- Menu item title that selects all documents in the current directory [CHAR LIMIT=24] -->
     <string name="menu_select_all">Select All</string>
+    <!-- Menu item title that copies the selected documents [CHAR LIMIT=24] -->
+    <string name="menu_copy">Copy to\u2026</string>
 
     <!-- Menu item that reveals internal storage built into the device [CHAR LIMIT=24] -->
     <string name="menu_advanced_show" product="nosdcard">Show internal storage</string>
@@ -110,4 +112,18 @@
     <!-- Title of dialog when prompting user to select an app to share documents with [CHAR LIMIT=32] -->
     <string name="share_via">Share via</string>
 
+    <!-- Title of the cancel button [CHAR LIMIT=24] -->
+    <string name="cancel">Cancel</string>
+    <!-- Title of the copy notification [CHAR LIMIT=24] -->
+    <string name="copy_notification_title">Copying files</string>
+    <!-- Text shown on the copy notification to indicate remaining time, in minutes [CHAR LIMIT=24] -->
+    <string name="copy_remaining"><xliff:g id="duration" example="3 minutes">%s</xliff:g> left</string>
+    <!-- Toast shown when a file copy is kicked off -->
+    <plurals name="copy_begin">
+      <item quantity="one">Copying <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
+      <item quantity="other">Copying <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
+    </plurals>
+    <!-- Text shown on the copy notification while DocumentsUI performs setup in preparation for copying files [CHAR LIMIT=32] -->
+    <string name="copy_preparing">Preparing for copy\u2026</string>
+
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index bf01bf1..39c958e 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -43,7 +43,7 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
     </style>
 
-    <style name="StandaloneTheme" parent="android:Theme.Light">
+    <style name="StandaloneTheme" parent="android:Theme.DeviceDefault.Light">
         <item name="android:actionBarWidgetTheme">@null</item>
         <item name="android:actionBarTheme">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
         <item name="android:actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
new file mode 100644
index 0000000..c826aba
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.app.IntentService;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentProviderClient;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import libcore.io.IoUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class CopyService extends IntentService {
+    public static final String TAG = "CopyService";
+    public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
+    private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
+
+    private NotificationManager mNotificationManager;
+    private Notification.Builder mProgressBuilder;
+
+    // Jobs are serialized but a job ID is used, to avoid mixing up cancellation requests.
+    private String mJobId;
+    private volatile boolean mIsCancelled;
+    // Parameters of the copy job. Requests to an IntentService are serialized so this code only
+    // needs to deal with one job at a time.
+    private final List<Uri> mFailedFiles;
+    private long mBatchSize;
+    private long mBytesCopied;
+    private long mStartTime;
+    private long mLastNotificationTime;
+    // Speed estimation
+    private long mBytesCopiedSample;
+    private long mSampleTime;
+    private long mSpeed;
+    private long mRemainingTime;
+    // Provider clients are acquired for the duration of each copy job. Note that there is an
+    // implicit assumption that all srcs come from the same authority.
+    private ContentProviderClient mSrcClient;
+    private ContentProviderClient mDstClient;
+
+    public CopyService() {
+        super("CopyService");
+
+        mFailedFiles = new ArrayList<Uri>();
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        if (intent.hasExtra(EXTRA_CANCEL)) {
+            handleCancel(intent);
+        }
+        return super.onStartCommand(intent, flags, startId);
+    }
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+        if (intent.hasExtra(EXTRA_CANCEL)) {
+            handleCancel(intent);
+            return;
+        }
+
+        ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST);
+        Uri destinationUri = intent.getData();
+
+        try {
+            // Acquire content providers.
+            mSrcClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(),
+                    srcs.get(0).authority);
+            mDstClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(),
+                    destinationUri.getAuthority());
+
+            setupCopyJob(srcs, destinationUri);
+
+            for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) {
+                copy(srcs.get(i), destinationUri);
+            }
+        } catch (Exception e) {
+            // Catch-all to prevent any copy errors from wedging the app.
+            Log.e(TAG, "Exceptions occurred during copying", e);
+        } finally {
+            ContentProviderClient.releaseQuietly(mSrcClient);
+            ContentProviderClient.releaseQuietly(mDstClient);
+
+            // Dismiss the ongoing copy notification when the copy is done.
+            mNotificationManager.cancel(mJobId, 0);
+
+            if (mFailedFiles.size() > 0) {
+                // TODO: Display a notification when an error has occurred.
+            }
+
+            // TODO: Display a toast if the copy was cancelled.
+        }
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+    }
+
+    /**
+     * Sets up the CopyService to start tracking and sending notifications for the given batch of
+     * files.
+     *
+     * @param srcs A list of src files to copy.
+     * @param destinationUri The URI of the destination directory.
+     * @throws RemoteException
+     */
+    private void setupCopyJob(ArrayList<DocumentInfo> srcs, Uri destinationUri)
+            throws RemoteException {
+        // Create an ID for this copy job. Use the timestamp.
+        mJobId = String.valueOf(SystemClock.elapsedRealtime());
+        // Reset the cancellation flag.
+        mIsCancelled = false;
+
+        mProgressBuilder = new Notification.Builder(this)
+                .setContentTitle(getString(R.string.copy_notification_title))
+                .setCategory(Notification.CATEGORY_PROGRESS)
+                .setSmallIcon(R.drawable.ic_menu_copy).setOngoing(true);
+
+        Intent cancelIntent = new Intent(this, CopyService.class);
+        cancelIntent.putExtra(EXTRA_CANCEL, mJobId);
+        mProgressBuilder.addAction(R.drawable.ic_cab_cancel,
+                getString(R.string.cancel), PendingIntent.getService(this, 0,
+                        cancelIntent, PendingIntent.FLAG_ONE_SHOT));
+
+        // TODO: Add a content intent to open the destination folder.
+
+        // Send an initial progress notification.
+        mProgressBuilder.setProgress(0, 0, true); // Indeterminate progress while setting up.
+        mProgressBuilder.setContentText(getString(R.string.copy_preparing));
+        mNotificationManager.notify(mJobId, 0, mProgressBuilder.build());
+
+        // Reset batch parameters.
+        mFailedFiles.clear();
+        mBatchSize = calculateFileSizes(srcs);
+        mBytesCopied = 0;
+        mStartTime = SystemClock.elapsedRealtime();
+        mLastNotificationTime = 0;
+        mBytesCopiedSample = 0;
+        mSampleTime = 0;
+        mSpeed = 0;
+        mRemainingTime = 0;
+
+        // TODO: Check preconditions for copy.
+        // - check that the destination has enough space and is writeable?
+        // - check MIME types?
+    }
+
+    /**
+     * Calculates the cumulative size of all the documents in the list. Directories are recursed
+     * into and totaled up.
+     *
+     * @param srcs
+     * @return Size in bytes.
+     * @throws RemoteException
+     */
+    private long calculateFileSizes(List<DocumentInfo> srcs) throws RemoteException {
+        long result = 0;
+        for (DocumentInfo src : srcs) {
+            if (Document.MIME_TYPE_DIR.equals(src.mimeType)) {
+                // Directories need to be recursed into.
+                result += calculateFileSizesHelper(src.derivedUri);
+            } else {
+                result += src.size;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Calculates (recursively) the cumulative size of all the files under the given directory.
+     *
+     * @throws RemoteException
+     */
+    private long calculateFileSizesHelper(Uri uri) throws RemoteException {
+        final String authority = uri.getAuthority();
+        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(authority,
+                DocumentsContract.getDocumentId(uri));
+        final String queryColumns[] = new String[] {
+                Document.COLUMN_DOCUMENT_ID,
+                Document.COLUMN_MIME_TYPE,
+                Document.COLUMN_SIZE
+        };
+
+        long result = 0;
+        Cursor cursor = null;
+        try {
+            cursor = mSrcClient.query(queryUri, queryColumns, null, null, null);
+            while (cursor.moveToNext()) {
+                if (Document.MIME_TYPE_DIR.equals(
+                        getCursorString(cursor, Document.COLUMN_MIME_TYPE))) {
+                    // Recurse into directories.
+                    final Uri subdirUri = DocumentsContract.buildDocumentUri(authority,
+                            getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
+                    result += calculateFileSizesHelper(subdirUri);
+                } else {
+                    // This may return -1 if the size isn't defined. Ignore those cases.
+                    long size = getCursorLong(cursor, Document.COLUMN_SIZE);
+                    result += size > 0 ? size : 0;
+                }
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+
+        return result;
+    }
+
+    /**
+     * Cancels the current copy job, if its ID matches the given ID.
+     *
+     * @param intent The cancellation intent.
+     */
+    private void handleCancel(Intent intent) {
+        final String cancelledId = intent.getStringExtra(EXTRA_CANCEL);
+        // Do nothing if the cancelled ID doesn't match the current job ID. This prevents racey
+        // cancellation requests from affecting unrelated copy jobs.
+        if (Objects.equals(mJobId, cancelledId)) {
+            // Set the cancel flag. This causes the copy loops to exit.
+            mIsCancelled = true;
+            // Dismiss the progress notification here rather than in the copy loop. This preserves
+            // interactivity for the user in case the copy loop is stalled.
+            mNotificationManager.cancel(mJobId, 0);
+        }
+    }
+
+    /**
+     * Logs progress on the current copy operation. Displays/Updates the progress notification.
+     *
+     * @param bytesCopied
+     */
+    private void makeProgress(long bytesCopied) {
+        mBytesCopied += bytesCopied;
+        double done = (double) mBytesCopied / mBatchSize;
+        String percent = NumberFormat.getPercentInstance().format(done);
+
+        // Update time estimate
+        long currentTime = SystemClock.elapsedRealtime();
+        long elapsedTime = currentTime - mStartTime;
+
+        // Send out progress notifications once a second.
+        if (currentTime - mLastNotificationTime > 1000) {
+            updateRemainingTimeEstimate(elapsedTime);
+            mProgressBuilder.setProgress(100, (int) (done * 100), false);
+            mProgressBuilder.setContentInfo(percent);
+            if (mRemainingTime > 0) {
+                mProgressBuilder.setContentText(getString(R.string.copy_remaining,
+                        DateUtils.formatDuration(mRemainingTime)));
+            } else {
+                mProgressBuilder.setContentText(null);
+            }
+            mNotificationManager.notify(mJobId, 0, mProgressBuilder.build());
+            mLastNotificationTime = currentTime;
+        }
+    }
+
+    /**
+     * Generates an estimate of the remaining time in the copy.
+     *
+     * @param elapsedTime The time elapsed so far.
+     */
+    private void updateRemainingTimeEstimate(long elapsedTime) {
+        final long sampleDuration = elapsedTime - mSampleTime;
+        final long sampleSpeed = ((mBytesCopied - mBytesCopiedSample) * 1000) / sampleDuration;
+        if (mSpeed == 0) {
+            mSpeed = sampleSpeed;
+        } else {
+            mSpeed = ((3 * mSpeed) + sampleSpeed) / 4;
+        }
+
+        if (mSampleTime > 0 && mSpeed > 0) {
+            mRemainingTime = ((mBatchSize - mBytesCopied) * 1000) / mSpeed;
+        } else {
+            mRemainingTime = 0;
+        }
+
+        mSampleTime = elapsedTime;
+        mBytesCopiedSample = mBytesCopied;
+    }
+
+    /**
+     * Copies a the given documents to the given location.
+     *
+     * @param srcInfo DocumentInfos for the documents to copy.
+     * @param dstDirUri The URI of the destination directory.
+     * @throws RemoteException
+     */
+    private void copy(DocumentInfo srcInfo, Uri dstDirUri) throws RemoteException {
+        final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirUri,
+                srcInfo.mimeType, srcInfo.displayName);
+        if (dstUri == null) {
+            // If this is a directory, the entire subdir will not be copied over.
+            Log.e(TAG, "Error while copying " + srcInfo.displayName);
+            mFailedFiles.add(srcInfo.derivedUri);
+            return;
+        }
+
+        if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) {
+            copyDirectoryHelper(srcInfo.derivedUri, dstUri);
+        } else {
+            copyFileHelper(srcInfo.derivedUri, dstUri);
+        }
+    }
+
+    /**
+     * Handles recursion into a directory and copying its contents. Note that in linux terms, this
+     * does the equivalent of "cp src/* dst", not "cp -r src dst".
+     *
+     * @param srcDirUri URI of the directory to copy from. The routine will copy the directory's
+     *            contents, not the directory itself.
+     * @param dstDirUri URI of the directory to copy to. Must be created beforehand.
+     * @throws RemoteException
+     */
+    private void copyDirectoryHelper(Uri srcDirUri, Uri dstDirUri) throws RemoteException {
+        // Recurse into directories. Copy children into the new subdirectory.
+        final String queryColumns[] = new String[] {
+                Document.COLUMN_DISPLAY_NAME,
+                Document.COLUMN_DOCUMENT_ID,
+                Document.COLUMN_MIME_TYPE,
+                Document.COLUMN_SIZE
+        };
+        final Uri queryUri = DocumentsContract.buildChildDocumentsUri(srcDirUri.getAuthority(),
+                DocumentsContract.getDocumentId(srcDirUri));
+        Cursor cursor = null;
+        try {
+            // Iterate over srcs in the directory; copy to the destination directory.
+            cursor = mSrcClient.query(queryUri, queryColumns, null, null, null);
+            while (cursor.moveToNext()) {
+                final String childMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+                final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirUri,
+                        childMimeType, getCursorString(cursor, Document.COLUMN_DISPLAY_NAME));
+                final Uri childUri = DocumentsContract.buildDocumentUri(srcDirUri.getAuthority(),
+                        getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
+                if (Document.MIME_TYPE_DIR.equals(childMimeType)) {
+                    copyDirectoryHelper(childUri, dstUri);
+                } else {
+                    copyFileHelper(childUri, dstUri);
+                }
+            }
+        } finally {
+            IoUtils.closeQuietly(cursor);
+        }
+    }
+
+    /**
+     * Handles copying a single file.
+     *
+     * @param srcUri URI of the file to copy from.
+     * @param dstUri URI of the *file* to copy to. Must be created beforehand.
+     * @throws RemoteException
+     */
+    private void copyFileHelper(Uri srcUri, Uri dstUri) throws RemoteException {
+        // Copy an individual file.
+        CancellationSignal canceller = new CancellationSignal();
+        ParcelFileDescriptor srcFile = null;
+        ParcelFileDescriptor dstFile = null;
+        InputStream src = null;
+        OutputStream dst = null;
+
+        boolean errorOccurred = false;
+        try {
+            srcFile = mSrcClient.openFile(srcUri, "r", canceller);
+            dstFile = mDstClient.openFile(dstUri, "w", canceller);
+            src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile);
+            dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile);
+
+            byte[] buffer = new byte[8192];
+            int len;
+            while (!mIsCancelled && ((len = src.read(buffer)) != -1)) {
+                dst.write(buffer, 0, len);
+                makeProgress(len);
+            }
+            srcFile.checkError();
+            dstFile.checkError();
+        } catch (IOException e) {
+            errorOccurred = true;
+            Log.e(TAG, "Error while copying " + srcUri.toString(), e);
+            mFailedFiles.add(srcUri);
+        } finally {
+            // This also ensures the file descriptors are closed.
+            IoUtils.closeQuietly(src);
+            IoUtils.closeQuietly(dst);
+        }
+
+        if (errorOccurred || mIsCancelled) {
+            // Clean up half-copied files.
+            canceller.cancel();
+            try {
+                DocumentsContract.deleteDocument(mDstClient, dstUri);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to clean up: " + srcUri, e);
+                // RemoteExceptions usually signal that the connection is dead, so there's no point
+                // attempting to continue. Propagate the exception up so the copy job is cancelled.
+                throw e;
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index a75dc42..0e3016d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -27,6 +27,7 @@
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -50,6 +51,7 @@
 import android.os.CancellationSignal;
 import android.os.OperationCanceledException;
 import android.os.Parcelable;
+import android.os.SystemProperties;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.text.format.DateUtils;
@@ -77,6 +79,7 @@
 import android.widget.Toast;
 
 import com.android.documentsui.BaseActivity.State;
+import com.android.documentsui.CopyService;
 import com.android.documentsui.ProviderExecutor.Preemptable;
 import com.android.documentsui.RecentsProvider.StateColumns;
 import com.android.documentsui.model.DocumentInfo;
@@ -97,6 +100,8 @@
 
     private AbsListView mCurrentView;
 
+    private List<DocumentInfo> mSelectedDocumentsForCopy;
+
     public static final int TYPE_NORMAL = 1;
     public static final int TYPE_SEARCH = 2;
     public static final int TYPE_RECENT_OPEN = 3;
@@ -106,6 +111,8 @@
     public static final int ANIM_DOWN = 3;
     public static final int ANIM_UP = 4;
 
+    public static final int REQUEST_COPY_DESTINATION = 1;
+
     private int mType = TYPE_NORMAL;
     private String mStateKey;
 
@@ -335,6 +342,41 @@
     }
 
     @Override
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+        final Context context = getActivity();
+        final Resources res = context.getResources();
+
+        // There's only one request code right now. Replace this with a switch statement or
+        // something more scalable when more codes are added.
+        if (requestCode != REQUEST_COPY_DESTINATION) {
+            return;
+        }
+        if (resultCode == Activity.RESULT_CANCELED || data == null) {
+            // User pressed the back button or otherwise cancelled the destination pick. Don't
+            // proceed with the copy.
+            return;
+        }
+
+        // Because the destination picker is launched using an open tree intent, the URI returned is
+        // a tree URI. Convert it to a document URI.
+        // TODO: Remove this step when the destination picker returns a document URI.
+        final Uri destinationTree = data.getData();
+        final Uri destination = DocumentsContract.buildDocumentUriUsingTree(destinationTree,
+                DocumentsContract.getTreeDocumentId(destinationTree));
+
+        List<DocumentInfo> docs = mSelectedDocumentsForCopy;
+        Intent copyIntent = new Intent(context, CopyService.class);
+        copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST,
+                new ArrayList<DocumentInfo>(docs));
+        copyIntent.setData(destination);
+
+        Toast.makeText(context,
+                res.getQuantityString(R.plurals.copy_begin, docs.size(), docs.size()),
+                Toast.LENGTH_SHORT).show();
+        context.startService(copyIntent);
+    }
+
+    @Override
     public void onStop() {
         super.onStop();
 
@@ -463,11 +505,16 @@
             final MenuItem open = menu.findItem(R.id.menu_open);
             final MenuItem share = menu.findItem(R.id.menu_share);
             final MenuItem delete = menu.findItem(R.id.menu_delete);
+            final MenuItem copy = menu.findItem(R.id.menu_copy);
 
             final boolean manageMode = state.action == ACTION_MANAGE;
             open.setVisible(!manageMode);
             share.setVisible(manageMode);
             delete.setVisible(manageMode);
+            // Hide the copy menu item in the recents folder. For now, also hide it by default
+            // unless the debug flag is enabled.
+            copy.setVisible((mType != TYPE_RECENT_OPEN) &&
+                    SystemProperties.getBoolean("debug.documentsui.enable_copy", false));
 
             return true;
         }
@@ -501,6 +548,11 @@
                 mode.finish();
                 return true;
 
+            } else if (id == R.id.menu_copy) {
+                onCopyDocuments(docs);
+                mode.finish();
+                return true;
+
             } else if (id == R.id.menu_select_all) {
                 int count = mCurrentView.getCount();
                 for (int i = 0; i < count; i++) {
@@ -530,9 +582,7 @@
                 if (cursor != null) {
                     final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
                     final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
-                    if (!Document.MIME_TYPE_DIR.equals(docMimeType)) {
-                        valid = isDocumentEnabled(docMimeType, docFlags);
-                    }
+                    valid = isDocumentEnabled(docMimeType, docFlags);
                 }
 
                 if (!valid) {
@@ -561,8 +611,17 @@
 
     private void onShareDocuments(List<DocumentInfo> docs) {
         Intent intent;
-        if (docs.size() == 1) {
-            final DocumentInfo doc = docs.get(0);
+
+        // Filter out directories - those can't be shared.
+        List<DocumentInfo> docsForSend = Lists.newArrayList();
+        for (DocumentInfo doc: docs) {
+            if (!Document.MIME_TYPE_DIR.equals(doc.mimeType)) {
+                docsForSend.add(doc);
+            }
+        }
+
+        if (docsForSend.size() == 1) {
+            final DocumentInfo doc = docsForSend.get(0);
 
             intent = new Intent(Intent.ACTION_SEND);
             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -570,14 +629,14 @@
             intent.setType(doc.mimeType);
             intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
 
-        } else if (docs.size() > 1) {
+        } else if (docsForSend.size() > 1) {
             intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
             intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
             intent.addCategory(Intent.CATEGORY_DEFAULT);
 
             final ArrayList<String> mimeTypes = Lists.newArrayList();
             final ArrayList<Uri> uris = Lists.newArrayList();
-            for (DocumentInfo doc : docs) {
+            for (DocumentInfo doc : docsForSend) {
                 mimeTypes.add(doc.mimeType);
                 uris.add(doc.derivedUri);
             }
@@ -623,6 +682,15 @@
         }
     }
 
+    private void onCopyDocuments(List<DocumentInfo> docs) {
+        mSelectedDocumentsForCopy = docs;
+
+        // Pop up a dialog to pick a destination.  This is inadequate but works for now.
+        // TODO: Implement a picker that is to spec.
+        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
+        startActivityForResult(intent, REQUEST_COPY_DESTINATION);
+    }
+
     private static State getDisplayState(Fragment fragment) {
         return ((BaseActivity) fragment.getActivity()).getDisplayState();
     }
diff --git a/packages/DocumentsUI/tests/AndroidManifest.xml b/packages/DocumentsUI/tests/AndroidManifest.xml
index 81a2889..a312427 100644
--- a/packages/DocumentsUI/tests/AndroidManifest.xml
+++ b/packages/DocumentsUI/tests/AndroidManifest.xml
@@ -4,6 +4,17 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <provider
+            android:name="com.android.documentsui.StubProvider"
+            android:authorities="com.android.documentsui.stubprovider"
+            android:exported="true"
+            android:grantUriPermissions="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS"
+            android:enabled="true">
+            <intent-filter>
+                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+            </intent-filter>
+       </provider>
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index cdb6b33..7faa3ce 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -19,7 +19,7 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 import com.google.android.collect.Lists;
 
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
new file mode 100644
index 0000000..6044781
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.database.MatrixCursor;
+import android.graphics.Point;
+import android.os.CancellationSignal;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+
+public class StubProvider extends DocumentsProvider {
+    private static int STORAGE_SIZE = 1024 * 1024;  // 1 MB.
+    private static final String TAG = "StubProvider";
+    private static final String MY_ROOT_ID = "myRoot";
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
+            Root.COLUMN_AVAILABLE_BYTES
+    };
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+    };
+
+    private String mRootDocumentId;
+    private HashMap<String, File> mStorage = new HashMap<String, File>();
+    private int mStorageUsedBytes;
+
+    @Override
+    public boolean onCreate() {
+        final File cacheDir = getContext().getCacheDir();
+        removeRecursively(cacheDir);
+        mRootDocumentId = getDocumentIdForFile(cacheDir);
+        mStorage.put(mRootDocumentId, cacheDir);
+        return true;
+    }
+
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
+        final RowBuilder row = result.newRow();
+        row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD);
+        row.add(Root.COLUMN_TITLE, "Foobar SD 4GB");
+        row.add(Root.COLUMN_DOCUMENT_ID, mRootDocumentId);
+        row.add(Root.COLUMN_AVAILABLE_BYTES, STORAGE_SIZE - mStorageUsedBytes);
+        return result;
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
+        final File file = mStorage.get(documentId);
+        if (file == null) {
+            throw new FileNotFoundException();
+        }
+        includeFile(result, file);
+        return result;
+    }
+
+    @Override
+    public boolean isChildDocument(String parentDocId, String docId) {
+        try {
+            final File parentFile = getFileForDocumentId(parentDocId).getCanonicalFile();
+            final File childFile = getFileForDocumentId(docId).getCanonicalFile();
+            return FileUtils.contains(parentFile, childFile);
+        } catch (IOException e) {
+            throw new IllegalArgumentException();
+        }
+    }
+
+    @Override
+    public String createDocument(String parentDocumentId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        final File parentFile = mStorage.get(parentDocumentId);
+        if (parentFile == null || !parentFile.isDirectory()) {
+            throw new FileNotFoundException();
+        }
+        final File file = new File(parentFile, displayName);
+        if (mimeType.equals(Document.MIME_TYPE_DIR)) {
+            if (!file.mkdirs()) {
+                throw new FileNotFoundException();
+            }
+        } else {
+            try {
+                if (!file.createNewFile()) {
+                    throw new FileNotFoundException();
+                }
+            }
+            catch (IOException e) {
+                throw new FileNotFoundException();
+            }
+        }
+
+        final String documentId = getDocumentIdForFile(file);
+        mStorage.put(documentId, file);
+        return documentId;
+    }
+
+    @Override
+    public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
+        final File parentFile = mStorage.get(parentDocumentId);
+        if (parentFile == null || parentFile.isFile()) {
+            throw new FileNotFoundException();
+        }
+        for (File file : parentFile.listFiles()) {
+            includeFile(result, file);
+        }
+        return result;
+    }
+
+    @Override
+    public Cursor queryRecentDocuments(String rootId, String[] projection)
+            throws FileNotFoundException {
+        throw new FileNotFoundException();
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        final File file = mStorage.get(docId);
+        if (file == null || !file.isFile())
+            throw new FileNotFoundException();
+        // TODO: Simulate running out of storage.
+        return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_WRITE);
+    }
+
+    @Override
+    public AssetFileDescriptor openDocumentThumbnail(
+            String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
+        throw new FileNotFoundException();
+    }
+
+    private void includeFile(MatrixCursor result, File file) {
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, getDocumentIdForFile(file));
+        row.add(Document.COLUMN_DISPLAY_NAME, file.getName());
+        row.add(Document.COLUMN_SIZE, file.length());
+        // TODO: Provide real mime type for files.
+        row.add(Document.COLUMN_MIME_TYPE, file.isDirectory() ? Document.MIME_TYPE_DIR : "application/octet-stream");
+        int flags = 0;
+        // TODO: Add support for renaming and deleting.
+        if (file.isDirectory()) {
+            flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
+        } else {
+            flags |= Document.FLAG_SUPPORTS_WRITE;
+        }
+        row.add(Document.COLUMN_FLAGS, flags);
+        row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified());
+    }
+
+    private String getDocumentIdForFile(File file) {
+        return file.getAbsolutePath();
+    }
+
+    private File getFileForDocumentId(String documentId) {
+        return new File(documentId);
+    }
+
+    private void removeRecursively(File file) {
+        for (File childFile : file.listFiles()) {
+            if (childFile.isDirectory()) {
+                removeRecursively(childFile);
+            }
+            childFile.delete();
+        }
+    }
+}
diff --git a/packages/Keyguard/Android.mk b/packages/Keyguard/Android.mk
index 96ed2e7..9083212 100644
--- a/packages/Keyguard/Android.mk
+++ b/packages/Keyguard/Android.mk
@@ -22,6 +22,8 @@
 
 LOCAL_CERTIFICATE := platform
 
+LOCAL_JAVA_LIBRARIES := SettingsLib
+
 LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
@@ -30,4 +32,4 @@
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
-#include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+#include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index e4b543b..c93f03b 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode is aanvaar!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen diens nie."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index c54656e..bd835f0 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ኮዱ ተቀባይነት አግኝቷል!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"የአውሮፕላን ሁነታ"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index 153f08e..f50d32b 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -117,4 +117,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"تم قبول الرمز!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"لا تتوفر خدمة"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"وضع الطائرة"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index 5dcb82c..c8d4391 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодът е приет!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Няма покритие."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml
index 2b13a07..399955f 100644
--- a/packages/Keyguard/res/values-bn-rBD/strings.xml
+++ b/packages/Keyguard/res/values-bn-rBD/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"কোড স্বীকৃত হয়েছে!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"কোনো পরিষেবা নেই৷"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"বিমান মোড"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index e675c7a..3af9f0a 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"S\'ha acceptat el codi."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sense servei."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index e1fa6f9..b3bae64 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -113,4 +113,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód byl přijat."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žádný signál."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index 77e8ce3..b330d16 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden blev accepteret."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index e21961d..d92acd5 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code akzeptiert"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Kein Dienst"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 7084c84..2a255a7 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Αποδεκτός κωδικός!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Καμία υπηρεσία."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-en-rAU/strings.xml b/packages/Keyguard/res/values-en-rAU/strings.xml
index ee5da13..55c33d9 100644
--- a/packages/Keyguard/res/values-en-rAU/strings.xml
+++ b/packages/Keyguard/res/values-en-rAU/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index ee5da13..55c33d9 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index ee5da13..55c33d9 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Aeroplane mode"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index b34dd05..86da3b4 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index be3c113..0bc19c4 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index 402fc14..e4dc8f3 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kood on õige."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index 86850bb..0a99dd9 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodea onartu da!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Zerbitzurik gabe."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Idazketa-metodoa aldatzeko botoia."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Hegaldi modua"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index 367c411..94ed51c 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کد پذیرفته شد!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"خدماتی وجود ندارد."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"حالت هواپیما"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index 68f7016..5153297 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koodi hyväksytty!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ei yhteyttä."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index 2c24f7a..bfe02da 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index 77a2d06..1f7e5b8 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml
index 8e8f5c5..0553e1d 100644
--- a/packages/Keyguard/res/values-gl-rES/strings.xml
+++ b/packages/Keyguard/res/values-gl-rES/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Non hai servizo."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Cambiar o botón do método de entrada."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Modo avión"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index 0cd65b8..d2b57c5 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकार किया गया!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कोई सेवा नहीं."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"हवाई जहाज़ मोड"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index 71410c5..68e0dbc 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -111,4 +111,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nema usluge."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index dd43dba..538add3 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód elfogadva."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nincs szolgáltatás."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index e56642a..80c5512 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Կոդն ընդունվեց:"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index 29a56ef..e943baf 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode Diterima!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tidak ada layanan."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Mode pesawat"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml
index 5741cd0..1054e60 100644
--- a/packages/Keyguard/res/values-is-rIS/strings.xml
+++ b/packages/Keyguard/res/values-is-rIS/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Númer samþykkt!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ekkert símasamband."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Hnappur til að skipta um innsláttaraðferð."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index c5c476c..8aed187 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Codice accettato."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nessun servizio."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index a856ccb..3ff01bb 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -113,4 +113,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"הקוד התקבל!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"אין קליטה."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"מצב טיסה"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index 5c76034..d3205d8 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"コードが承認されました。"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"通信サービスはありません。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index e9c77fd..940a17e 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"კოდი მიღებულია!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml
index 85443f6..587c87b 100644
--- a/packages/Keyguard/res/values-kk-rKZ/strings.xml
+++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код қабылданды!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Қызмет көрсетілмейді."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index be72fd6..31e8fb5 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"បាន​ទទួល​យក​លេខ​កូដ​!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មាន​សេវា​"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"របៀបក្នុងយន្តហោះ"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml
index cfa1ac0..626e07c 100644
--- a/packages/Keyguard/res/values-kn-rIN/strings.xml
+++ b/packages/Keyguard/res/values-kn-rIN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ಕೋಡ್ ಅಂಗೀಕೃತವಾಗಿದೆ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ಯಾವುದೇ ಸೇವೆಯಿಲ್ಲ."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index 1ef0c19..aa4a388 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"코드 승인 완료"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"서비스 불가"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index 430c19a..0045a3c 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код кабыл алынды!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Байланыш жок."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index 17c1c5b..047c4aa 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ລະ​ຫັດ​ຖືກຕອບຮັບແລ້ວ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"ໂໝດໃນຍົນ"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index 6d7dcc7..bafa7c3 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -113,4 +113,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodas priimtas."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nėra paslaugos."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index e1da889..5aee3c9 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -111,4 +111,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kods ir pieņemts!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nav pakalpojuma."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml
index 717671b..fc9be77 100644
--- a/packages/Keyguard/res/values-mk-rMK/strings.xml
+++ b/packages/Keyguard/res/values-mk-rMK/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодот е прифатен!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нема услуга."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml
index f39a6b7..616e416 100644
--- a/packages/Keyguard/res/values-ml-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ml-rIN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"കോഡ് അംഗികരിച്ചു!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"സേവനമൊന്നുമില്ല."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"ഫ്ലൈറ്റ് മോഡ്"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 2f24901..8b6e31b 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код зөвшөөрөгдлөө!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Нислэгийн горим"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index a86bf60..34a26f8 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्‍वीकारला!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"सेवा नाही."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"विमान मोड"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index 3d4dee4..3b9379a 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Diterima!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Mod Pesawat"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml
index 4432ceb..d8554c1 100644
--- a/packages/Keyguard/res/values-my-rMM/strings.xml
+++ b/packages/Keyguard/res/values-my-rMM/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ကုဒ်နံပါတ်ကို လက်ခံလိုက်ပါသည်"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ဆားဗစ် မရှိပါ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"လေယာဉ်ပေါ်သုံးစနစ်"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index efc25cf..eab4d47 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden er godkjent."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjeneste."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index 7f6843a..d694f8c 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकृत!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कुनै सेवा छैन।"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"हवाइजहाज मोड"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 3a8d91c..f46c311 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code geaccepteerd."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen service"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 40cd5e6..60c67ae 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -113,4 +113,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod został zaakceptowany."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Brak usługi."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 9068898..a9bcb0e 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceite!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index 690b693..ba138de 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceito."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Modo avião"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index 0c11689..eb4ab59 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -111,4 +111,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Cod acceptat!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Fără serviciu."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 48fd4f6..5f8dbd2 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -113,4 +113,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код принят"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нет сигнала."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml
index 740b0ea..ac0dc1c 100644
--- a/packages/Keyguard/res/values-si-rLK/strings.xml
+++ b/packages/Keyguard/res/values-si-rLK/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"කේතය පිළිගැණුනි!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"සේවාව නැත."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"ගුවන්යානා ප්‍රකාරය"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index 2fbe838..8990cfc 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -113,4 +113,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód bol prijatý!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žiadny signál"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Režim v lietadle"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index a79d99a..900d9bb 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -113,4 +113,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koda je sprejeta."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ni storitve."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index b7c439b..01f795e 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -111,4 +111,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кôд је прихваћен!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 75adc2c..c3c3b34 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden godkändes!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjänst."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 886c22e..d7130be 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Msimbo Umekubaliwa!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hakuna huduma."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Hali ya ndegeni"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml
index 89c1480..e763aa6 100644
--- a/packages/Keyguard/res/values-ta-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ta-rIN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"குறியீடு ஏற்கப்பட்டது!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"சேவை இல்லை."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"விமானப் பயன்முறை"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml
index 2f51742..0ffc202 100644
--- a/packages/Keyguard/res/values-te-rIN/strings.xml
+++ b/packages/Keyguard/res/values-te-rIN/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"కోడ్ ఆమోదించబడింది!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"సేవ లేదు."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"ఎయిర్‌ప్లైన్ మోడ్"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 6d0d026..5466c02 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"รหัสได้รับการยอมรับ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ไม่มีบริการ"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 8125efe..a74666d 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Tinanggap ang Code!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Walang serbisyo."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Airplane mode"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index aa32baa..33479d9 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Kabul Edildi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hizmet yok."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index 9e52283..fe02464 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -113,4 +113,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код прийнято."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Зв’язку немає."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Режим польоту"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml
index 5cd54c0..ab3c229 100644
--- a/packages/Keyguard/res/values-ur-rPK/strings.xml
+++ b/packages/Keyguard/res/values-ur-rPK/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کوڈ قبول کر لیا گیا!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"کوئی سروس نہیں ہے۔"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml
index a6852a7..85f4da1 100644
--- a/packages/Keyguard/res/values-uz-rUZ/strings.xml
+++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod qabul qilindi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aloqa yo‘q."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Kiritish uslubi tugmasini almashtirish."</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Parvoz rejimi"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 5727900..51adada 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Mã được chấp nhận!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Không có dịch vụ."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index a93b54b..2e2e202 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 55a6a5e..41831e4 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"飛航模式"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index 66c665f..a66cbfa 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -109,4 +109,6 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
+    <!-- no translation found for airplane_mode (3122107900897202805) -->
+    <skip />
 </resources>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index be8900a..4de6e8b 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -109,4 +109,5 @@
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Ikhodi yamukelwe!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ayikho isevisi."</string>
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
+    <string name="airplane_mode" msgid="3122107900897202805">"Isimo sendiza"</string>
 </resources>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 5047330..df221fa 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -123,7 +123,7 @@
     <string name="keyboardview_keycode_enter">Enter</string>
 
     <!-- Label shown on emergency call button in keyguard -->
-    <string name="kg_emergency_call_label">Emergency call</string>
+    <string name="kg_emergency_call_label">Emergency</string>
     <!-- Message shown in pattern unlock after some number of unsuccessful attempts -->
     <string name="kg_forgot_pattern_button_text">Forgot Pattern</string>
     <!-- Message shown when user enters wrong pattern -->
@@ -300,4 +300,10 @@
     <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_ime_switch_button" msgid="5032926134740456424">Switch input method button.</string>
 
+    <!-- Description of airplane mode -->
+    <string name="airplane_mode">Airplane mode</string>
+
+    <!-- Fingerprint hint message when finger was not recognized.-->
+    <string name="fingerprint_not_recognized">Not recognized</string>
+
 </resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/CarrierText.java b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
index 7d0b81d..4fbcc1e 100644
--- a/packages/Keyguard/src/com/android/keyguard/CarrierText.java
+++ b/packages/Keyguard/src/com/android/keyguard/CarrierText.java
@@ -35,6 +35,7 @@
 import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.settingslib.WirelessUtils;
 
 public class CarrierText extends TextView {
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -146,6 +147,9 @@
                         getContext().getText(R.string.keyguard_missing_sim_message_short), text);
             }
         }
+        if (WirelessUtils.isAirplaneModeOn(mContext)) {
+            displayText = getContext().getString(R.string.airplane_mode);
+        }
         setText(displayText);
     }
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index c9805ae..5a4d5cd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -53,10 +53,10 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 
-import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
-import android.service.fingerprint.FingerprintUtils;
-import android.service.fingerprint.FingerprintManager.AuthenticationResult;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
+import android.hardware.fingerprint.FingerprintUtils;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
@@ -149,6 +149,7 @@
     private boolean mScreenOn;
     private SubscriptionManager mSubscriptionManager;
     private List<SubscriptionInfo> mSubscriptionInfo;
+    private boolean mFingerprintDetectionRunning;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -332,27 +333,35 @@
     }
 
     private void handleFingerprintAuthenticated(int fingerId, int groupId) {
-        if (fingerId == 0) return; // not a valid fingerprint
+        if (fingerId == 0) {
+            // not a valid fingerprint
+            handleFingerprintHelp(-1, mContext.getString(R.string.fingerprint_not_recognized));
+            return;
+        }
 
-        final int userId;
         try {
-            userId = ActivityManagerNative.getDefault().getCurrentUser().id;
-        } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get current user id: ", e);
-            return;
-        }
-        if (isFingerprintDisabled(userId)) {
-            Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
-            return;
-        }
-        final ContentResolver res = mContext.getContentResolver();
-        final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
-        for (int i = 0; i < ids.length; i++) {
-            // TODO: fix once HAL supports storing group id
-            final boolean isCorrectUser = true || (groupId == userId);
-            if (ids[i] == fingerId && isCorrectUser) {
-                onFingerprintAuthenticated(userId);
+            final int userId;
+            try {
+                userId = ActivityManagerNative.getDefault().getCurrentUser().id;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to get current user id: ", e);
+                return;
             }
+            if (isFingerprintDisabled(userId)) {
+                Log.d(TAG, "Fingerprint disabled by DPM for userId: " + userId);
+                return;
+            }
+            final ContentResolver res = mContext.getContentResolver();
+            final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
+            for (int i = 0; i < ids.length; i++) {
+                // TODO: fix once HAL supports storing group id
+                final boolean isCorrectUser = true || (groupId == userId);
+                if (ids[i] == fingerId && isCorrectUser) {
+                    onFingerprintAuthenticated(userId);
+                }
+            }
+        } finally {
+            setFingerprintRunningDetectionRunning(false);
         }
     }
 
@@ -366,6 +375,7 @@
     }
 
     private void handleFingerprintError(int msgId, String errString) {
+        setFingerprintRunningDetectionRunning(false);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -374,6 +384,21 @@
         }
     }
 
+    private void setFingerprintRunningDetectionRunning(boolean running) {
+        if (running != mFingerprintDetectionRunning) {
+            mFingerprintDetectionRunning = running;
+            notifyFingerprintRunningStateChanged();
+        }
+    }
+
+    private void notifyFingerprintRunningStateChanged() {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onFingerprintRunningStateChanged(mFingerprintDetectionRunning);
+            }
+        }
+    }
     private void handleFaceUnlockStateChanged(boolean running, int userId) {
         mUserFaceUnlockRunning.put(userId, running);
         for (int i = 0; i < mCallbacks.size(); i++) {
@@ -388,6 +413,10 @@
         return mUserFaceUnlockRunning.get(userId);
     }
 
+    public boolean isFingerprintDetectionRunning() {
+        return mFingerprintDetectionRunning;
+    }
+
     private boolean isTrustDisabled(int userId) {
         // Don't allow trust agent if device is secured with a SIM PIN. This is here
         // mainly because there's no other way to prompt the user to enter their SIM PIN
@@ -736,13 +765,15 @@
     }
 
     private void startListeningForFingerprint(Context context) {
-        if (mFpm != null && mFpm.isHardwareDetected()) {
+        if (mFpm != null && mFpm.isHardwareDetected()
+                && mFpm.getEnrolledFingerprints().size() > 0) {
             if (mFingerprintCancelSignal == null) {
                 mFingerprintCancelSignal = new CancellationSignal();
             } else {
                 mFingerprintCancelSignal.cancel();
             }
             mFpm.authenticate(null, mAuthenticationCallback, mFingerprintCancelSignal, 0);
+            setFingerprintRunningDetectionRunning(true);
         }
     }
 
@@ -750,6 +781,7 @@
         if (mFingerprintCancelSignal != null) {
             mFingerprintCancelSignal.cancel();
         }
+        setFingerprintRunningDetectionRunning(false);
     }
 
     private boolean isDeviceProvisionedInSettingsDb() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index c2462e0..756a7a4 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,7 +19,7 @@
 import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.os.SystemClock;
-import android.service.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager;
 import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicy;
 
@@ -200,4 +200,9 @@
      * Called when the state of face unlock changed.
      */
     public void onFaceUnlockStateChanged(boolean running, int userId) { }
+
+    /**
+     * Called when the fingerprint running state changed.
+     */
+    public void onFingerprintRunningStateChanged(boolean running) { }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
old mode 100755
new mode 100644
index e1cb878..dd2368f
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -104,6 +104,7 @@
 
     // See mConnectAttempted
     private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+    private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
 
     /** Auto-connect after pairing only if locally initiated. */
     private boolean mConnectAfterPairing;
@@ -525,19 +526,25 @@
      */
     void onUuidChanged() {
         updateProfiles();
+        ParcelUuid[] uuids = mDevice.getUuids();
+
+        long timeout = MAX_UUID_DELAY_FOR_AUTO_CONNECT;
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) {
+            timeout = MAX_HOGP_DELAY_FOR_AUTO_CONNECT;
+        }
 
         if (DEBUG) {
-            Log.e(TAG, "onUuidChanged: Time since last connect"
+            Log.d(TAG, "onUuidChanged: Time since last connect"
                     + (SystemClock.elapsedRealtime() - mConnectAttempted));
         }
 
         /*
-         * If a connect was attempted earlier without any UUID, we will do the
-         * connect now.
+         * If a connect was attempted earlier without any UUID, we will do the connect now.
+         * Otherwise, allow the connect on UUID change.
          */
         if (!mProfiles.isEmpty()
-                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
-                        .elapsedRealtime()) {
+                && ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime()
+                || (mConnectAttempted == 0))) {
             connectWithoutResettingTimer(false);
         }
         dispatchAttributesChanged();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 729efcb..0b6ab99 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -61,10 +61,18 @@
 import java.util.Set;
 
 /**
- * Database helper class for {@link SettingsProvider}.
- * Mostly just has a bit {@link #onCreate} to initialize the database.
+ * Legacy settings database helper class for {@link SettingsProvider}.
+ *
+ * IMPORTANT: Do not add any more upgrade steps here as the global,
+ * secure, and system settings are no longer stored in a database
+ * but are kept in memory and persisted to XML.
+ *
+ * See: SettingsProvider.UpgradeController#onUpgradeLocked
+ *
+ * @deprecated The implementation is frozen.  Do not add any new code to this class!
  */
-public class DatabaseHelper extends SQLiteOpenHelper {
+@Deprecated
+class DatabaseHelper extends SQLiteOpenHelper {
     private static final String TAG = "SettingsProvider";
     private static final String DATABASE_NAME = "settings.db";
 
@@ -1932,19 +1940,14 @@
             upgradeVersion = 118;
         }
 
-        /**
+        /*
          * IMPORTANT: Do not add any more upgrade steps here as the global,
          * secure, and system settings are no longer stored in a database
-         * but are kept in memory and persisted to XML. The correct places
-         * for adding upgrade steps are:
+         * but are kept in memory and persisted to XML.
          *
-         * Global: SettingsProvider.UpgradeController#onUpgradeGlobalSettings
-         * Secure: SettingsProvider.UpgradeController#onUpgradeSecureSettings
-         * System: SettingsProvider.UpgradeController#onUpgradeSystemSettings
+         * See: SettingsProvider.UpgradeController#onUpgradeLocked
          */
 
-        // *** Remember to update DATABASE_VERSION above!
-
         if (upgradeVersion != currentVersion) {
             recreateDatabase(db, oldVersion, upgradeVersion, currentVersion);
         }
@@ -2386,6 +2389,14 @@
 
             loadIntegerSetting(stmt, Settings.System.POINTER_SPEED,
                     R.integer.def_pointer_speed);
+
+            /*
+             * IMPORTANT: Do not add any more upgrade steps here as the global,
+             * secure, and system settings are no longer stored in a database
+             * but are kept in memory and persisted to XML.
+             *
+             * See: SettingsProvider.UpgradeController#onUpgradeLocked
+             */
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -2517,6 +2528,14 @@
 
             loadIntegerSetting(stmt, Settings.Secure.SLEEP_TIMEOUT,
                     R.integer.def_sleep_timeout);
+
+            /*
+             * IMPORTANT: Do not add any more upgrade steps here as the global,
+             * secure, and system settings are no longer stored in a database
+             * but are kept in memory and persisted to XML.
+             *
+             * See: SettingsProvider.UpgradeController#onUpgradeLocked
+             */
         } finally {
             if (stmt != null) stmt.close();
         }
@@ -2693,7 +2712,14 @@
                     R.bool.def_guest_user_enabled);
             loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
                     ImsConfig.FeatureValueConstants.ON);
-            // --- New global settings start here
+
+            /*
+             * IMPORTANT: Do not add any more upgrade steps here as the global,
+             * secure, and system settings are no longer stored in a database
+             * but are kept in memory and persisted to XML.
+             *
+             * See: SettingsProvider.UpgradeController#onUpgradeLocked
+             */
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 8328d112..0d61606 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1502,15 +1502,15 @@
         public void onPackageRemovedLocked(String packageName, int userId) {
             final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
             SettingsState globalSettings = mSettingsStates.get(globalKey);
-            globalSettings.onPackageRemovedLocked(packageName);
+            if (globalSettings != null) globalSettings.onPackageRemovedLocked(packageName);
 
             final int secureKey = makeKey(SETTINGS_TYPE_SECURE, userId);
             SettingsState secureSettings = mSettingsStates.get(secureKey);
-            secureSettings.onPackageRemovedLocked(packageName);
+            if (secureSettings != null) secureSettings.onPackageRemovedLocked(packageName);
 
             final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
             SettingsState systemSettings = mSettingsStates.get(systemKey);
-            systemSettings.onPackageRemovedLocked(packageName);
+            if (systemSettings != null) systemSettings.onPackageRemovedLocked(packageName);
         }
 
         private SettingsState peekSettingsStateLocked(int key) {
@@ -1859,40 +1859,43 @@
                 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
             }
 
+            /**
+             * You must perform all necessary mutations to bring the settings
+             * for this user from the old to the new version. When you add a new
+             * upgrade step you *must* update SETTINGS_VERSION.
+             *
+             * This is an example of moving a setting from secure to global.
+             *
+             * // v119: Example settings changes.
+             * if (currentVersion == 118) {
+             *     if (userId == UserHandle.USER_OWNER) {
+             *         // Remove from the secure settings.
+             *         SettingsState secureSettings = getSecureSettingsLocked(userId);
+             *         String name = "example_setting_to_move";
+             *         String value = secureSettings.getSetting(name);
+             *         secureSettings.deleteSetting(name);
+             *
+             *         // Add to the global settings.
+             *         SettingsState globalSettings = getGlobalSettingsLocked();
+             *         globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
+             *     }
+             *
+             *     // Update the current version.
+             *     currentVersion = 119;
+             * }
+             */
             private int onUpgradeLocked(int userId, int oldVersion, int newVersion) {
                 if (DEBUG) {
                     Slog.w(LOG_TAG, "Upgrading settings for user: " + userId + " from version: "
                             + oldVersion + " to version: " + newVersion);
                 }
 
-                // You must perform all necessary mutations to bring the settings
-                // for this user from the old to the new version. When you add a new
-                // upgrade step you *must* update SETTINGS_VERSION.
+                int currentVersion = oldVersion;
 
-                /**
-                 * This is an example of moving a setting from secure to global.
-                 *
-                 * int currentVersion = oldVersion;
-                 * if (currentVersion == 118) {
-                 *     // Remove from the secure settings.
-                 *     SettingsState secureSettings = getSecureSettingsLocked(userId);
-                 *     String name = "example_setting_to_move";
-                 *     String value = secureSettings.getSetting(name);
-                 *     secureSettings.deleteSetting(name);
-                 *
-                 *     // Add to the global settings.
-                 *     SettingsState globalSettings = getGlobalSettingsLocked();
-                 *     globalSettings.insertSetting(name, value, SettingsState.SYSTEM_PACKAGE_NAME);
-                 *
-                 *     // Update the current version.
-                 *     currentVersion = 119;
-                 * }
-                 *
-                 * // Return the current version.
-                 * return currentVersion;
-                 */
+                // vXXX: Add new settings above this point.
 
-                return SettingsState.VERSION_UNDEFINED;
+                // Return the current version.
+                return currentVersion;
             }
         }
     }
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9d16501..35e9636 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -93,6 +93,7 @@
     <uses-permission android:name="android.permission.BIND_APPWIDGET" />
     <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" />
     <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/>
+    <uses-permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS" />
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/StatementService/Android.mk b/packages/StatementService/Android.mk
new file mode 100644
index 0000000..470d824
--- /dev/null
+++ b/packages/StatementService/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := StatementService
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_JAVA_LIBRARIES += org.apache.http.legacy
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    libprotobuf-java-nano \
+    volley
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH)/src)
diff --git a/packages/StatementService/AndroidManifest.xml b/packages/StatementService/AndroidManifest.xml
new file mode 100644
index 0000000..3ee453b
--- /dev/null
+++ b/packages/StatementService/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.statementservice"
+        android:versionCode="1"
+        android:versionName="1.0">
+
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"/>
+
+    <application
+            android:label="@string/service_name"
+            android:allowBackup="false">
+        <service
+                android:name=".DirectStatementService"
+                android:exported="false">
+            <intent-filter>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <action android:name="com.android.statementservice.aosp.service.CHECK_ACTION"/>
+            </intent-filter>
+        </service>
+
+        <receiver
+                android:name=".IntentFilterVerificationReceiver"
+                android:permission="android.permission.BIND_INTENT_FILTER_VERIFIER">
+            <!-- Set the priority 1 so newer implementation can have higher priority. -->
+            <intent-filter
+                    android:priority="1">
+                <action android:name="android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"/>
+                <data android:mimeType="application/vnd.android.package-archive"/>
+            </intent-filter>
+        </receiver>
+
+    </application>
+
+</manifest>
diff --git a/packages/StatementService/proguard.flags b/packages/StatementService/proguard.flags
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/packages/StatementService/proguard.flags
diff --git a/packages/StatementService/res/values/strings.xml b/packages/StatementService/res/values/strings.xml
new file mode 100644
index 0000000..df6d80b
--- /dev/null
+++ b/packages/StatementService/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="service_name">Intent Filter Verification Service</string>
+</resources>
diff --git a/packages/StatementService/src/com/android/statementservice/DirectStatementService.java b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
new file mode 100644
index 0000000..449738e
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/DirectStatementService.java
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice;
+
+import android.app.Service;
+import android.content.Intent;
+import android.net.http.HttpResponseCache;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.ResultReceiver;
+import android.util.Log;
+
+import com.android.statementservice.retriever.AbstractAsset;
+import com.android.statementservice.retriever.AbstractAssetMatcher;
+import com.android.statementservice.retriever.AbstractStatementRetriever;
+import com.android.statementservice.retriever.AbstractStatementRetriever.Result;
+import com.android.statementservice.retriever.AssociationServiceException;
+import com.android.statementservice.retriever.Relation;
+import com.android.statementservice.retriever.Statement;
+
+import org.json.JSONException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+/**
+ * Handles com.android.statementservice.service.CHECK_ALL_ACTION intents.
+ */
+public final class DirectStatementService extends Service {
+    private static final String TAG = DirectStatementService.class.getSimpleName();
+
+    /**
+     * Returns true if every asset in {@code SOURCE_ASSET_DESCRIPTORS} is associated with {@code
+     * EXTRA_TARGET_ASSET_DESCRIPTOR} for {@code EXTRA_RELATION} relation.
+     *
+     * <p>Takes parameter {@code EXTRA_RELATION}, {@code SOURCE_ASSET_DESCRIPTORS}, {@code
+     * EXTRA_TARGET_ASSET_DESCRIPTOR}, and {@code EXTRA_RESULT_RECEIVER}.
+     */
+    public static final String CHECK_ALL_ACTION =
+            "com.android.statementservice.service.CHECK_ALL_ACTION";
+
+    /**
+     * Parameter for {@link #CHECK_ALL_ACTION}.
+     *
+     * <p>A relation string.
+     */
+    public static final String EXTRA_RELATION =
+            "com.android.statementservice.service.RELATION";
+
+    /**
+     * Parameter for {@link #CHECK_ALL_ACTION}.
+     *
+     * <p>An array of asset descriptors in JSON.
+     */
+    public static final String EXTRA_SOURCE_ASSET_DESCRIPTORS =
+            "com.android.statementservice.service.SOURCE_ASSET_DESCRIPTORS";
+
+    /**
+     * Parameter for {@link #CHECK_ALL_ACTION}.
+     *
+     * <p>An asset descriptor in JSON.
+     */
+    public static final String EXTRA_TARGET_ASSET_DESCRIPTOR =
+            "com.android.statementservice.service.TARGET_ASSET_DESCRIPTOR";
+
+    /**
+     * Parameter for {@link #CHECK_ALL_ACTION}.
+     *
+     * <p>A {@code ResultReceiver} instance that will be used to return the result. If the request
+     * failed, return {@link #RESULT_FAIL} and an empty {@link android.os.Bundle}. Otherwise, return
+     * {@link #RESULT_SUCCESS} and a {@link android.os.Bundle} with the result stored in {@link
+     * #IS_ASSOCIATED}.
+     */
+    public static final String EXTRA_RESULT_RECEIVER =
+            "com.android.statementservice.service.RESULT_RECEIVER";
+
+    /**
+     * A boolean bundle entry that stores the result of {@link #CHECK_ALL_ACTION}.
+     * This is set only if the service returns with {@code RESULT_SUCCESS}.
+     * {@code IS_ASSOCIATED} is true if and only if {@code FAILED_SOURCES} is empty.
+     */
+    public static final String IS_ASSOCIATED = "is_associated";
+
+    /**
+     * A String ArrayList bundle entry that stores sources that can't be verified.
+     */
+    public static final String FAILED_SOURCES = "failed_sources";
+
+    /**
+     * Returned by the service if the request is successfully processed. The caller should check
+     * the {@code IS_ASSOCIATED} field to determine if the association exists or not.
+     */
+    public static final int RESULT_SUCCESS = 0;
+
+    /**
+     * Returned by the service if the request failed. The request will fail if, for example, the
+     * input is not well formed, or the network is not available.
+     */
+    public static final int RESULT_FAIL = 1;
+
+    private static final long HTTP_CACHE_SIZE_IN_BYTES = 1 * 1024 * 1024;  // 1 MBytes
+    private static final String CACHE_FILENAME = "request_cache";
+
+    private AbstractStatementRetriever mStatementRetriever;
+    private Handler mHandler;
+    private HandlerThread mThread;
+    private HttpResponseCache mHttpResponseCache;
+
+    @Override
+    public void onCreate() {
+        mThread = new HandlerThread("DirectStatementService thread",
+                android.os.Process.THREAD_PRIORITY_BACKGROUND);
+        mThread.start();
+        onCreate(AbstractStatementRetriever.createDirectRetriever(this), mThread.getLooper(),
+                getCacheDir());
+    }
+
+    /**
+     * Creates a DirectStatementService with the dependencies passed in for easy testing.
+     */
+    public void onCreate(AbstractStatementRetriever statementRetriever, Looper looper,
+                         File cacheDir) {
+        super.onCreate();
+        mStatementRetriever = statementRetriever;
+        mHandler = new Handler(looper);
+
+        try {
+            File httpCacheDir = new File(cacheDir, CACHE_FILENAME);
+            mHttpResponseCache = HttpResponseCache.install(httpCacheDir, HTTP_CACHE_SIZE_IN_BYTES);
+        } catch (IOException e) {
+            Log.i(TAG, "HTTPS response cache installation failed:" + e);
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (mThread != null) {
+            mThread.quit();
+        }
+
+        try {
+            if (mHttpResponseCache != null) {
+                mHttpResponseCache.delete();
+            }
+        } catch (IOException e) {
+            Log.i(TAG, "HTTP(S) response cache deletion failed:" + e);
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        super.onStartCommand(intent, flags, startId);
+
+        if (intent == null) {
+            Log.e(TAG, "onStartCommand called with null intent");
+            return START_STICKY;
+        }
+
+        if (intent.getAction().equals(CHECK_ALL_ACTION)) {
+
+            Bundle extras = intent.getExtras();
+            List<String> sources = extras.getStringArrayList(EXTRA_SOURCE_ASSET_DESCRIPTORS);
+            String target = extras.getString(EXTRA_TARGET_ASSET_DESCRIPTOR);
+            String relation = extras.getString(EXTRA_RELATION);
+            ResultReceiver resultReceiver = extras.getParcelable(EXTRA_RESULT_RECEIVER);
+
+            if (resultReceiver == null) {
+                Log.e(TAG, " Intent does not have extra " + EXTRA_RESULT_RECEIVER);
+                return START_STICKY;
+            }
+            if (sources == null) {
+                Log.e(TAG, " Intent does not have extra " + EXTRA_SOURCE_ASSET_DESCRIPTORS);
+                resultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
+                return START_STICKY;
+            }
+            if (target == null) {
+                Log.e(TAG, " Intent does not have extra " + EXTRA_TARGET_ASSET_DESCRIPTOR);
+                resultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
+                return START_STICKY;
+            }
+            if (relation == null) {
+                Log.e(TAG, " Intent does not have extra " + EXTRA_RELATION);
+                resultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
+                return START_STICKY;
+            }
+
+            mHandler.post(new ExceptionLoggingFutureTask<Void>(
+                    new IsAssociatedCallable(sources, target, relation, resultReceiver), TAG));
+        } else {
+            Log.e(TAG, "onStartCommand called with unsupported action: " + intent.getAction());
+        }
+        return START_STICKY;
+    }
+
+    private class IsAssociatedCallable implements Callable<Void> {
+
+        private List<String> mSources;
+        private String mTarget;
+        private String mRelation;
+        private ResultReceiver mResultReceiver;
+
+        public IsAssociatedCallable(List<String> sources, String target, String relation,
+                ResultReceiver resultReceiver) {
+            mSources = sources;
+            mTarget = target;
+            mRelation = relation;
+            mResultReceiver = resultReceiver;
+        }
+
+        private boolean verifyOneSource(AbstractAsset source, AbstractAssetMatcher target,
+                Relation relation) throws AssociationServiceException {
+            Result statements = mStatementRetriever.retrieveStatements(source);
+            for (Statement statement : statements.getStatements()) {
+                if (relation.matches(statement.getRelation())
+                        && target.matches(statement.getTarget())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public Void call() {
+            Bundle result = new Bundle();
+            ArrayList<String> failedSources = new ArrayList<String>();
+            AbstractAssetMatcher target;
+            Relation relation;
+            try {
+                target = AbstractAssetMatcher.createMatcher(mTarget);
+                relation = Relation.create(mRelation);
+            } catch (AssociationServiceException | JSONException e) {
+                Log.e(TAG, "isAssociatedCallable failed with exception", e);
+                mResultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
+                return null;
+            }
+
+            boolean allSourcesVerified = true;
+            for (String sourceString : mSources) {
+                AbstractAsset source;
+                try {
+                    source = AbstractAsset.create(sourceString);
+                } catch (AssociationServiceException e) {
+                    mResultReceiver.send(RESULT_FAIL, Bundle.EMPTY);
+                    return null;
+                }
+
+                try {
+                    if (!verifyOneSource(source, target, relation)) {
+                        failedSources.add(source.toJson());
+                        allSourcesVerified = false;
+                    }
+                } catch (AssociationServiceException e) {
+                    failedSources.add(source.toJson());
+                    allSourcesVerified = false;
+                }
+            }
+
+            result.putBoolean(IS_ASSOCIATED, allSourcesVerified);
+            result.putStringArrayList(FAILED_SOURCES, failedSources);
+            mResultReceiver.send(RESULT_SUCCESS, result);
+            return null;
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java b/packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java
new file mode 100644
index 0000000..20c7f97
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/ExceptionLoggingFutureTask.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice;
+
+import android.util.Log;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * {@link FutureTask} that logs unhandled exceptions.
+ */
+final class ExceptionLoggingFutureTask<V> extends FutureTask<V> {
+
+    private final String mTag;
+
+    public ExceptionLoggingFutureTask(Callable<V> callable, String tag) {
+        super(callable);
+        mTag = tag;
+    }
+
+    @Override
+    protected void done() {
+        try {
+            get();
+        } catch (ExecutionException | InterruptedException e) {
+            Log.e(mTag, "Uncaught exception.", e);
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
new file mode 100644
index 0000000..712347a
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/IntentFilterVerificationReceiver.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.util.Log;
+import android.util.Patterns;
+
+import com.android.statementservice.retriever.Utils;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/**
+ * Receives {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION} broadcast and calls
+ * {@link DirectStatementService} to verify the request. Calls
+ * {@link PackageManager#verifyIntentFilter} to notify {@link PackageManager} the result of the
+ * verification.
+ *
+ * This implementation of the API will send a HTTP request for each host specified in the query.
+ * To avoid overwhelming the network at app install time, {@code MAX_HOSTS_PER_REQUEST} limits
+ * the maximum number of hosts in a query. If a query contains more than
+ * {@code MAX_HOSTS_PER_REQUEST} hosts, it will fail immediately without making any HTTP request
+ * and call {@link PackageManager#verifyIntentFilter} with
+ * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
+ */
+public final class IntentFilterVerificationReceiver extends BroadcastReceiver {
+    private static final String TAG = IntentFilterVerificationReceiver.class.getSimpleName();
+
+    private static final Integer MAX_HOSTS_PER_REQUEST = 10;
+
+    private static final String HANDLE_ALL_URLS_RELATION
+            = "delegate_permission/common.handle_all_urls";
+
+    private static final String ANDROID_ASSET_FORMAT = "{\"namespace\": \"android_app\", "
+            + "\"package_name\": \"%s\", \"sha256_cert_fingerprints\": [\"%s\"]}";
+    private static final String WEB_ASSET_FORMAT = "{\"namespace\": \"web\", \"site\": \"%s\"}";
+    private static final Pattern ANDROID_PACKAGE_NAME_PATTERN =
+            Pattern.compile("^[a-zA-Z_][a-zA-Z0-9_]*(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$");
+    private static final String TOO_MANY_HOSTS_FORMAT =
+            "Request contains %d hosts which is more than the allowed %d.";
+
+    private static void sendErrorToPackageManager(PackageManager packageManager,
+            int verificationId) {
+        packageManager.verifyIntentFilter(verificationId,
+                PackageManager.INTENT_FILTER_VERIFICATION_FAILURE,
+                Collections.<String>emptyList());
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        final String action = intent.getAction();
+        if (Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION.equals(action)) {
+            Bundle inputExtras = intent.getExtras();
+            if (inputExtras != null) {
+                Intent serviceIntent = new Intent(context, DirectStatementService.class);
+                serviceIntent.setAction(DirectStatementService.CHECK_ALL_ACTION);
+
+                int verificationId = inputExtras.getInt(
+                        PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_ID);
+                String scheme = inputExtras.getString(
+                        PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_URI_SCHEME);
+                String hosts = inputExtras.getString(
+                        PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_HOSTS);
+                String packageName = inputExtras.getString(
+                        PackageManager.EXTRA_INTENT_FILTER_VERIFICATION_PACKAGE_NAME);
+
+                Log.i(TAG, "Verify IntentFilter for " + hosts);
+
+                Bundle extras = new Bundle();
+                extras.putString(DirectStatementService.EXTRA_RELATION, HANDLE_ALL_URLS_RELATION);
+
+                String[] hostList = hosts.split(" ");
+                if (hostList.length > MAX_HOSTS_PER_REQUEST) {
+                    Log.w(TAG, String.format(TOO_MANY_HOSTS_FORMAT,
+                            hostList.length, MAX_HOSTS_PER_REQUEST));
+                    sendErrorToPackageManager(context.getPackageManager(), verificationId);
+                    return;
+                }
+
+                try {
+                    ArrayList<String> sourceAssets = new ArrayList<String>();
+                    for (String host : hostList) {
+                        sourceAssets.add(createWebAssetString(scheme, host));
+                    }
+                    extras.putStringArrayList(DirectStatementService.EXTRA_SOURCE_ASSET_DESCRIPTORS,
+                            sourceAssets);
+                } catch (MalformedURLException e) {
+                    Log.w(TAG, "Error when processing input host: " + e.getMessage());
+                    sendErrorToPackageManager(context.getPackageManager(), verificationId);
+                    return;
+                }
+                try {
+                    extras.putString(DirectStatementService.EXTRA_TARGET_ASSET_DESCRIPTOR,
+                            createAndroidAssetString(context, packageName));
+                } catch (NameNotFoundException e) {
+                    Log.w(TAG, "Error when processing input Android package: " + e.getMessage());
+                    sendErrorToPackageManager(context.getPackageManager(), verificationId);
+                    return;
+                }
+                extras.putParcelable(DirectStatementService.EXTRA_RESULT_RECEIVER,
+                        new IsAssociatedResultReceiver(
+                                new Handler(), context.getPackageManager(), verificationId));
+
+                serviceIntent.putExtras(extras);
+                context.startService(serviceIntent);
+            }
+        } else {
+            Log.w(TAG, "Intent action not supported: " + action);
+        }
+    }
+
+    private String createAndroidAssetString(Context context, String packageName)
+            throws NameNotFoundException {
+        if (!ANDROID_PACKAGE_NAME_PATTERN.matcher(packageName).matches()) {
+            throw new NameNotFoundException("Input package name is not valid.");
+        }
+
+        List<String> certFingerprints =
+                Utils.getCertFingerprintsFromPackageManager(packageName, context);
+
+        return String.format(ANDROID_ASSET_FORMAT, packageName,
+                Utils.joinStrings("\", \"", certFingerprints));
+    }
+
+    private String createWebAssetString(String scheme, String host) throws MalformedURLException {
+        if (!Patterns.DOMAIN_NAME.matcher(host).matches()) {
+            throw new MalformedURLException("Input host is not valid.");
+        }
+        if (!scheme.equals("http") && !scheme.equals("https")) {
+            throw new MalformedURLException("Input scheme is not valid.");
+        }
+
+        return String.format(WEB_ASSET_FORMAT, new URL(scheme, host, "").toString());
+    }
+
+    /**
+     * Receives the result of {@code StatementService.CHECK_ACTION} from
+     * {@link DirectStatementService} and passes it back to {@link PackageManager}.
+     */
+    private static class IsAssociatedResultReceiver extends ResultReceiver {
+
+        private final int mVerificationId;
+        private final PackageManager mPackageManager;
+
+        public IsAssociatedResultReceiver(Handler handler, PackageManager packageManager,
+                int verificationId) {
+            super(handler);
+            mVerificationId = verificationId;
+            mPackageManager = packageManager;
+        }
+
+        @Override
+        protected void onReceiveResult(int resultCode, Bundle resultData) {
+            if (resultCode == DirectStatementService.RESULT_SUCCESS) {
+                if (resultData.getBoolean(DirectStatementService.IS_ASSOCIATED)) {
+                    mPackageManager.verifyIntentFilter(mVerificationId,
+                            PackageManager.INTENT_FILTER_VERIFICATION_SUCCESS,
+                            Collections.<String>emptyList());
+                } else {
+                    mPackageManager.verifyIntentFilter(mVerificationId,
+                            PackageManager.INTENT_FILTER_VERIFICATION_FAILURE,
+                            resultData.getStringArrayList(DirectStatementService.FAILED_SOURCES));
+                }
+            } else {
+                sendErrorToPackageManager(mPackageManager, mVerificationId);
+            }
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
new file mode 100644
index 0000000..e71cf54
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAsset.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+/**
+ * A handle representing the identity and address of some digital asset. An asset is an online
+ * entity that typically provides some service or content. Examples of assets are websites, Android
+ * apps, Twitter feeds, and Plus Pages.
+ *
+ * <p> Asset can be represented by a JSON string. For example, the web site https://www.google.com
+ * can be represented by
+ * <pre>
+ * {"namespace": "web", "site": "https://www.google.com"}
+ * </pre>
+ *
+ * <p> The Android app with package name com.google.test that is signed by a certificate with sha256
+ * fingerprint 11:22:33 can be represented by
+ * <pre>
+ * {"namespace": "android_app",
+ *  "package_name": "com.google.test",
+ *  "sha256_cert_fingerprints": ["11:22:33"]}
+ * </pre>
+ *
+ * <p>Given a signed APK, Java 7's commandline keytool can compute the fingerprint using:
+ * {@code keytool -list -printcert -jarfile signed_app.apk}
+ */
+public abstract class AbstractAsset {
+
+    /**
+     * Returns a JSON string representation of this asset. The strings returned by this function are
+     * normalized -- they can be used for equality testing.
+     */
+    public abstract String toJson();
+
+    /**
+     * Returns a key that can be used by {@link AbstractAssetMatcher} to lookup the asset.
+     *
+     * <p> An asset will match an {@code AssetMatcher} only if the value of this method is equal to
+     * {@code AssetMatcher.getMatchedLookupKey()}.
+     */
+    public abstract int lookupKey();
+
+    /**
+     * Creates a new Asset from its JSON string representation.
+     *
+     * @throws AssociationServiceException if the assetJson is not well formatted.
+     */
+    public static AbstractAsset create(String assetJson)
+            throws AssociationServiceException {
+        return AssetFactory.create(assetJson);
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractAssetMatcher.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAssetMatcher.java
new file mode 100644
index 0000000..c35553f
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractAssetMatcher.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import org.json.JSONException;
+
+/**
+ * An asset matcher that can match asset with the given query.
+ */
+public abstract class AbstractAssetMatcher {
+
+    /**
+     * Returns true if this AssetMatcher matches the asset.
+     */
+    public abstract boolean matches(AbstractAsset asset);
+
+    /**
+     * This AssetMatcher will only match Asset with {@code lookupKey()} equal to the value returned
+     * by this method.
+     */
+    public abstract int getMatchedLookupKey();
+
+    /**
+     * Creates a new AssetMatcher from its JSON string representation.
+     *
+     * <p> For web namespace, {@code query} will match assets that have the same 'site' field.
+     *
+     * <p> For Android namespace, {@code query} will match assets that have the same
+     * 'package_name' field and have at least one common certificate fingerprint in
+     * 'sha256_cert_fingerprints' field.
+     */
+    public static AbstractAssetMatcher createMatcher(String query)
+            throws AssociationServiceException, JSONException {
+        return AssetMatcherFactory.create(query);
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
new file mode 100644
index 0000000..fb30bc1
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import android.content.Context;
+import android.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Retrieves the statements made by assets. This class is the entry point of the package.
+ * <p>
+ * An asset is an identifiable and addressable online entity that typically
+ * provides some service or content. Examples of assets are websites, Android
+ * apps, Twitter feeds, and Plus Pages.
+ * <p>
+ * Ownership of an asset is defined by being able to control it and speak for it.
+ * An asset owner may establish a relationship between the asset and another
+ * asset by making a statement about an intended relationship between the two.
+ * An example of a relationship is permission delegation. For example, the owner
+ * of a website (the webmaster) may delegate the ability the handle URLs to a
+ * particular mobile app. Relationships are considered public information.
+ * <p>
+ * A particular kind of relationship (like permission delegation) defines a binary
+ * relation on assets. The relation is not symmetric or transitive, nor is it
+ * antisymmetric or anti-transitive.
+ * <p>
+ * A statement S(r, a, b) is an assertion that the relation r holds for the
+ * ordered pair of assets (a, b). For example, taking r = "delegates permission
+ * to view user's location", a = New York Times mobile app,
+ * b = nytimes.com website, S(r, a, b) would be an assertion that "the New York
+ * Times mobile app delegates its ability to use the user's location to the
+ * nytimes.com website".
+ * <p>
+ * A statement S(r, a, b) is considered <b>reliable</b> if we have confidence that
+ * the statement is true; the exact criterion depends on the kind of statement,
+ * since some kinds of statements may be true on their face whereas others may
+ * require multiple parties to agree.
+ * <p>
+ * For example, to get the statements made by www.example.com use:
+ * <pre>
+ * result = retrieveStatements(AssetFactory.create(
+ *     "{\"namespace\": \"web\", \"site\": \"https://www.google.com\"}"))
+ * </pre>
+ * {@code result} will contain the statements and the expiration time of this result. The statements
+ * are considered reliable until the expiration time.
+ */
+public abstract class AbstractStatementRetriever {
+
+    /**
+     * Returns the statements made by the {@code source} asset with ttl.
+     *
+     * @throws AssociationServiceException if the asset namespace is not supported.
+     */
+    public abstract Result retrieveStatements(AbstractAsset source)
+            throws AssociationServiceException;
+
+    /**
+     * The retrieved statements and the expiration date.
+     */
+    public interface Result {
+
+        /**
+         * @return the retrieved statements.
+         */
+        @NonNull
+        public List<Statement> getStatements();
+
+        /**
+         * @return the expiration time in millisecond.
+         */
+        public long getExpireMillis();
+    }
+
+    /**
+     * Creates a new StatementRetriever that directly retrieves statements from the asset.
+     *
+     * <p> For web assets, {@link AbstractStatementRetriever} will try to retrieve the statement
+     * file from URL: {@code [webAsset.site]/.well-known/associations.json"} where {@code
+     * [webAsset.site]} is in the form {@code http{s}://[hostname]:[optional_port]}. The file
+     * should contain one JSON array of statements.
+     *
+     * <p> For Android assets, {@link AbstractStatementRetriever} will try to retrieve the statement
+     * from the AndroidManifest.xml. The developer should add a {@code meta-data} tag under
+     * {@code application} tag where attribute {@code android:name} equals "associated_assets"
+     * and {@code android:recourse} points to a string array resource. Each entry in the string
+     * array should contain exactly one statement in JSON format. Note that this implementation
+     * can only return statements made by installed apps.
+     */
+    public static AbstractStatementRetriever createDirectRetriever(Context context) {
+        return new DirectStatementRetriever(new URLFetcher(),
+                new AndroidPackageInfoFetcher(context));
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
new file mode 100644
index 0000000..0c96038
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAsset.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Immutable value type that names an Android app asset.
+ *
+ * <p>An Android app can be named by its package name and certificate fingerprints using this JSON
+ * string: { "namespace": "android_app", "package_name": "[Java package name]",
+ * "sha256_cert_fingerprints": ["[SHA256 fingerprint of signing cert]", "[additional cert]", ...] }
+ *
+ * <p>For example, { "namespace": "android_app", "package_name": "com.test.mytestapp",
+ * "sha256_cert_fingerprints": ["24:D9:B4:57:A6:42:FB:E6:E5:B8:D6:9E:7B:2D:C2:D1:CB:D1:77:17:1D:7F:D4:A9:16:10:11:AB:92:B9:8F:3F"]
+ * }
+ *
+ * <p>Given a signed APK, Java 7's commandline keytool can compute the fingerprint using:
+ * {@code keytool -list -printcert -jarfile signed_app.apk}
+ *
+ * <p>Each entry in "sha256_cert_fingerprints" is a colon-separated hex string (e.g. 14:6D:E9:...)
+ * representing the certificate SHA-256 fingerprint.
+ */
+/* package private */ final class AndroidAppAsset extends AbstractAsset {
+
+    private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set.";
+    private static final String MISSING_APPCERTS_FORMAT_STRING =
+            "Expected %s to be non-empty array.";
+    private static final String APPCERT_NOT_STRING_FORMAT_STRING = "Expected all %s to be strings.";
+
+    private final List<String> mCertFingerprints;
+    private final String mPackageName;
+
+    public List<String> getCertFingerprints() {
+        return Collections.unmodifiableList(mCertFingerprints);
+    }
+
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    @Override
+    public String toJson() {
+        AssetJsonWriter writer = new AssetJsonWriter();
+
+        writer.writeFieldLower(Utils.NAMESPACE_FIELD, Utils.NAMESPACE_ANDROID_APP);
+        writer.writeFieldLower(Utils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME, mPackageName);
+        writer.writeArrayUpper(Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS, mCertFingerprints);
+
+        return writer.closeAndGetString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder asset = new StringBuilder();
+        asset.append("AndroidAppAsset: ");
+        asset.append(toJson());
+        return asset.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof AndroidAppAsset)) {
+            return false;
+        }
+
+        return ((AndroidAppAsset) o).toJson().equals(toJson());
+    }
+
+    @Override
+    public int hashCode() {
+        return toJson().hashCode();
+    }
+
+    @Override
+    public int lookupKey() {
+        return getPackageName().hashCode();
+    }
+
+    /**
+     * Checks that the input is a valid Android app asset.
+     *
+     * @param asset a JSONObject that has "namespace", "package_name", and
+     *              "sha256_cert_fingerprints" fields.
+     * @throws AssociationServiceException if the asset is not well formatted.
+     */
+    public static AndroidAppAsset create(JSONObject asset)
+            throws AssociationServiceException {
+        String packageName = asset.optString(Utils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME);
+        if (packageName.equals("")) {
+            throw new AssociationServiceException(String.format(MISSING_FIELD_FORMAT_STRING,
+                    Utils.ANDROID_APP_ASSET_FIELD_PACKAGE_NAME));
+        }
+
+        JSONArray certArray = asset.optJSONArray(Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS);
+        if (certArray == null || certArray.length() == 0) {
+            throw new AssociationServiceException(
+                    String.format(MISSING_APPCERTS_FORMAT_STRING,
+                            Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS));
+        }
+        List<String> certFingerprints = new ArrayList<>(certArray.length());
+        for (int i = 0; i < certArray.length(); i++) {
+            try {
+                certFingerprints.add(certArray.getString(i));
+            } catch (JSONException e) {
+                throw new AssociationServiceException(
+                        String.format(APPCERT_NOT_STRING_FORMAT_STRING,
+                                Utils.ANDROID_APP_ASSET_FIELD_CERT_FPS));
+            }
+        }
+
+        return new AndroidAppAsset(packageName, certFingerprints);
+    }
+
+    /**
+     * Creates a new AndroidAppAsset.
+     *
+     * @param packageName the package name of the Android app.
+     * @param certFingerprints at least one of the Android app signing certificate sha-256
+     *                         fingerprint.
+     */
+    public static AndroidAppAsset create(String packageName, List<String> certFingerprints) {
+        if (packageName == null || packageName.equals("")) {
+            throw new AssertionError("Expected packageName to be set.");
+        }
+        if (certFingerprints == null || certFingerprints.size() == 0) {
+            throw new AssertionError("Expected certFingerprints to be set.");
+        }
+        List<String> lowerFps = new ArrayList<String>(certFingerprints.size());
+        for (String fp : certFingerprints) {
+            lowerFps.add(fp.toUpperCase(Locale.US));
+        }
+        return new AndroidAppAsset(packageName, lowerFps);
+    }
+
+    private AndroidAppAsset(String packageName, List<String> certFingerprints) {
+        if (packageName.equals("")) {
+            mPackageName = null;
+        } else {
+            mPackageName = packageName;
+        }
+
+        if (certFingerprints == null || certFingerprints.size() == 0) {
+            mCertFingerprints = null;
+        } else {
+            mCertFingerprints = Collections.unmodifiableList(sortAndDeDuplicate(certFingerprints));
+        }
+    }
+
+    /**
+     * Returns an ASCII-sorted copy of the list of certs with all duplicates removed.
+     */
+    private List<String> sortAndDeDuplicate(List<String> certs) {
+        if (certs.size() <= 1) {
+            return certs;
+        }
+        HashSet<String> set = new HashSet<>(certs);
+        List<String> result = new ArrayList<>(set);
+        Collections.sort(result);
+        return result;
+    }
+
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java
new file mode 100644
index 0000000..8a9d838
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidAppAssetMatcher.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Match assets that have the same 'package_name' field and have at least one common certificate
+ * fingerprint in 'sha256_cert_fingerprints' field.
+ */
+/* package private */ final class AndroidAppAssetMatcher extends AbstractAssetMatcher {
+
+    private final AndroidAppAsset mQuery;
+
+    public AndroidAppAssetMatcher(AndroidAppAsset query) {
+        mQuery = query;
+    }
+
+    @Override
+    public boolean matches(AbstractAsset asset) {
+        if (asset instanceof AndroidAppAsset) {
+            AndroidAppAsset androidAppAsset = (AndroidAppAsset) asset;
+            if (!androidAppAsset.getPackageName().equals(mQuery.getPackageName())) {
+                return false;
+            }
+
+            Set<String> certs = new HashSet<String>(mQuery.getCertFingerprints());
+            for (String cert : androidAppAsset.getCertFingerprints()) {
+                if (certs.contains(cert)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int getMatchedLookupKey() {
+        return mQuery.lookupKey();
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java
new file mode 100644
index 0000000..1000c4c
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AndroidPackageInfoFetcher.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources.NotFoundException;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class that provides information about an android app from {@link PackageManager}.
+ *
+ * Visible for testing.
+ *
+ * @hide
+ */
+public class AndroidPackageInfoFetcher {
+
+    /**
+     * The name of the metadata tag in AndroidManifest.xml that stores the associated asset array
+     * ID. The metadata tag should use the android:resource attribute to point to an array resource
+     * that contains the associated assets.
+     */
+    private static final String ASSOCIATED_ASSETS_KEY = "associated_assets";
+
+    private Context mContext;
+
+    public AndroidPackageInfoFetcher(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Returns the Sha-256 fingerprints of all certificates from the specified package as a list of
+     * upper case HEX Strings with bytes separated by colons. Given an app {@link
+     * android.content.pm.Signature}, the fingerprint can be computed as {@link
+     * Utils#computeNormalizedSha256Fingerprint} {@code(signature.toByteArray())}.
+     *
+     * <p>Given a signed APK, Java 7's commandline keytool can compute the fingerprint using: {@code
+     * keytool -list -printcert -jarfile signed_app.apk}
+     *
+     * <p>Example: "10:39:38:EE:45:37:E5:9E:8E:E7:92:F6:54:50:4F:B8:34:6F:C6:B3:46:D0:BB:C4:41:5F:C3:39:FC:FC:8E:C1"
+     *
+     * @throws NameNotFoundException if an app with packageName is not installed on the device.
+     */
+    public List<String> getCertFingerprints(String packageName) throws NameNotFoundException {
+        return Utils.getCertFingerprintsFromPackageManager(packageName, mContext);
+    }
+
+    /**
+     * Returns all statements that the specified package makes in its AndroidManifest.xml.
+     *
+     * @throws NameNotFoundException if the app is not installed on the device.
+     */
+    public List<String> getStatements(String packageName) throws NameNotFoundException {
+        PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo(
+                packageName, PackageManager.GET_META_DATA);
+        ApplicationInfo appInfo = packageInfo.applicationInfo;
+        if (appInfo.metaData == null) {
+            return Collections.<String>emptyList();
+        }
+        int tokenResourceId = appInfo.metaData.getInt(ASSOCIATED_ASSETS_KEY);
+        if (tokenResourceId == 0) {
+            return Collections.<String>emptyList();
+        }
+        try {
+            return Arrays.asList(
+                    mContext.getPackageManager().getResourcesForApplication(packageName)
+                    .getStringArray(tokenResourceId));
+        } catch (NotFoundException e) {
+            return Collections.<String>emptyList();
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java b/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java
new file mode 100644
index 0000000..762365e
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AssetFactory.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Factory to create asset from JSON string.
+ */
+/* package private */ final class AssetFactory {
+
+    private static final String FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string.";
+
+    private AssetFactory() {}
+
+    /**
+     * Creates a new Asset object from its JSON string representation.
+     *
+     * @throws AssociationServiceException if the assetJson is not well formatted.
+     */
+    public static AbstractAsset create(String assetJson) throws AssociationServiceException {
+        try {
+            return create(new JSONObject(assetJson));
+        } catch (JSONException e) {
+            throw new AssociationServiceException(
+                    "Input is not a well formatted asset descriptor.");
+        }
+    }
+
+    /**
+     * Checks that the input is a valid asset with purposes.
+     *
+     * @throws AssociationServiceException if the asset is not well formatted.
+     */
+    private static AbstractAsset create(JSONObject asset)
+            throws AssociationServiceException {
+        String namespace = asset.optString(Utils.NAMESPACE_FIELD, null);
+        if (namespace == null) {
+            throw new AssociationServiceException(String.format(
+                    FIELD_NOT_STRING_FORMAT_STRING, Utils.NAMESPACE_FIELD));
+        }
+
+        if (namespace.equals(Utils.NAMESPACE_WEB)) {
+            return WebAsset.create(asset);
+        } else if (namespace.equals(Utils.NAMESPACE_ANDROID_APP)) {
+            return AndroidAppAsset.create(asset);
+        } else {
+            throw new AssociationServiceException("Namespace " + namespace + " is not supported.");
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AssetJsonWriter.java b/packages/StatementService/src/com/android/statementservice/retriever/AssetJsonWriter.java
new file mode 100644
index 0000000..080e45a
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AssetJsonWriter.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import android.util.JsonWriter;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Creates a Json string where the order of the fields can be specified.
+ */
+/* package private */ final class AssetJsonWriter {
+
+    private StringWriter mStringWriter = new StringWriter();
+    private JsonWriter mWriter;
+    private boolean mClosed = false;
+
+    public AssetJsonWriter() {
+        mWriter = new JsonWriter(mStringWriter);
+        try {
+            mWriter.beginObject();
+        } catch (IOException e) {
+            throw new AssertionError("Unreachable exception.");
+        }
+    }
+
+    /**
+     * Appends a field to the output, putting both the key and value in lowercase. Null values are
+     * not written.
+     */
+    public void writeFieldLower(String key, String value) {
+        if (mClosed) {
+            throw new IllegalArgumentException(
+                    "Cannot write to an object that has already been closed.");
+        }
+
+        if (value != null) {
+            try {
+                mWriter.name(key.toLowerCase(Locale.US));
+                mWriter.value(value.toLowerCase(Locale.US));
+            } catch (IOException e) {
+                throw new AssertionError("Unreachable exception.");
+            }
+        }
+    }
+
+    /**
+     * Appends an array to the output, putting both the key and values in lowercase. If {@code
+     * values} is null, this field will not be written. Individual values in the list must not be
+     * null.
+     */
+    public void writeArrayUpper(String key, List<String> values) {
+        if (mClosed) {
+            throw new IllegalArgumentException(
+                    "Cannot write to an object that has already been closed.");
+        }
+
+        if (values != null) {
+            try {
+                mWriter.name(key.toLowerCase(Locale.US));
+                mWriter.beginArray();
+                for (String value : values) {
+                    mWriter.value(value.toUpperCase(Locale.US));
+                }
+                mWriter.endArray();
+            } catch (IOException e) {
+                throw new AssertionError("Unreachable exception.");
+            }
+        }
+    }
+
+    /**
+     * Returns the string representation of the constructed json. After calling this method, {@link
+     * #writeFieldLower} can no longer be called.
+     */
+    public String closeAndGetString() {
+        if (!mClosed) {
+            try {
+                mWriter.endObject();
+            } catch (IOException e) {
+                throw new AssertionError("Unreachable exception.");
+            }
+            mClosed = true;
+        }
+        return mStringWriter.toString();
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java b/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java
new file mode 100644
index 0000000..1a50757
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AssetMatcherFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Factory to create asset matcher from JSON string.
+ */
+/* package private */ final class AssetMatcherFactory {
+
+    private static final String FIELD_NOT_STRING_FORMAT_STRING = "Expected %s to be string.";
+    private static final String NAMESPACE_NOT_SUPPORTED_STRING = "Namespace %s is not supported.";
+
+    public static AbstractAssetMatcher create(String query) throws AssociationServiceException,
+            JSONException {
+        JSONObject queryObject = new JSONObject(query);
+
+        String namespace = queryObject.optString(Utils.NAMESPACE_FIELD, null);
+        if (namespace == null) {
+            throw new AssociationServiceException(String.format(
+                    FIELD_NOT_STRING_FORMAT_STRING, Utils.NAMESPACE_FIELD));
+        }
+
+        if (namespace.equals(Utils.NAMESPACE_WEB)) {
+            return new WebAssetMatcher(WebAsset.create(queryObject));
+        } else if (namespace.equals(Utils.NAMESPACE_ANDROID_APP)) {
+            return new AndroidAppAssetMatcher(AndroidAppAsset.create(queryObject));
+        } else {
+            throw new AssociationServiceException(
+                    String.format(NAMESPACE_NOT_SUPPORTED_STRING, namespace));
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AssociationServiceException.java b/packages/StatementService/src/com/android/statementservice/retriever/AssociationServiceException.java
new file mode 100644
index 0000000..d6e49c2
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AssociationServiceException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+/**
+ * Thrown when an error occurs in the Association Service.
+ */
+public class AssociationServiceException extends Exception {
+
+    public AssociationServiceException(String msg) {
+        super(msg);
+    }
+
+    public AssociationServiceException(String msg, Exception e) {
+        super(msg, e);
+    }
+
+    public AssociationServiceException(Exception e) {
+        super(e);
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
new file mode 100644
index 0000000..3ad71c4
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * An implementation of {@link AbstractStatementRetriever} that directly retrieves statements from
+ * the asset.
+ */
+/* package private */ final class DirectStatementRetriever extends AbstractStatementRetriever {
+
+    private static final long DO_NOT_CACHE_RESULT = 0L;
+    private static final int HTTP_CONNECTION_TIMEOUT_MILLIS = 5000;
+    private static final long HTTP_CONTENT_SIZE_LIMIT_IN_BYTES = 1024 * 1024;
+    private static final int MAX_INCLUDE_LEVEL = 1;
+    private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/associations.json";
+
+    private final URLFetcher mUrlFetcher;
+    private final AndroidPackageInfoFetcher mAndroidFetcher;
+
+    /**
+     * An immutable value type representing the retrieved statements and the expiration date.
+     */
+    public static class Result implements AbstractStatementRetriever.Result {
+
+        private final List<Statement> mStatements;
+        private final Long mExpireMillis;
+
+        @Override
+        public List<Statement> getStatements() {
+            return mStatements;
+        }
+
+        @Override
+        public long getExpireMillis() {
+            return mExpireMillis;
+        }
+
+        private Result(List<Statement> statements, Long expireMillis) {
+            mStatements = statements;
+            mExpireMillis = expireMillis;
+        }
+
+        public static Result create(List<Statement> statements, Long expireMillis) {
+            return new Result(statements, expireMillis);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder result = new StringBuilder();
+            result.append("Result: ");
+            result.append(mStatements.toString());
+            result.append(", mExpireMillis=");
+            result.append(mExpireMillis);
+            return result.toString();
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            Result result = (Result) o;
+
+            if (!mExpireMillis.equals(result.mExpireMillis)) {
+                return false;
+            }
+            if (!mStatements.equals(result.mStatements)) {
+                return false;
+            }
+
+            return true;
+        }
+
+        @Override
+        public int hashCode() {
+            int result = mStatements.hashCode();
+            result = 31 * result + mExpireMillis.hashCode();
+            return result;
+        }
+    }
+
+    public DirectStatementRetriever(URLFetcher urlFetcher,
+                                    AndroidPackageInfoFetcher androidFetcher) {
+        this.mUrlFetcher = urlFetcher;
+        this.mAndroidFetcher = androidFetcher;
+    }
+
+    @Override
+    public Result retrieveStatements(AbstractAsset source) throws AssociationServiceException {
+        if (source instanceof AndroidAppAsset) {
+            return retrieveFromAndroid((AndroidAppAsset) source);
+        } else if (source instanceof WebAsset) {
+            return retrieveFromWeb((WebAsset) source);
+        } else {
+            throw new AssociationServiceException("Namespace is not supported.");
+        }
+    }
+
+    private String computeAssociationJsonUrl(WebAsset asset) {
+        try {
+            return new URL(asset.getScheme(), asset.getDomain(), asset.getPort(),
+                    WELL_KNOWN_STATEMENT_PATH)
+                    .toExternalForm();
+        } catch (MalformedURLException e) {
+            throw new AssertionError("Invalid domain name in database.");
+        }
+    }
+
+    private Result retrieveStatementFromUrl(String url, int maxIncludeLevel, AbstractAsset source)
+            throws AssociationServiceException {
+        List<Statement> statements = new ArrayList<Statement>();
+        if (maxIncludeLevel < 0) {
+            return Result.create(statements, DO_NOT_CACHE_RESULT);
+        }
+
+        WebContent webContent;
+        try {
+            webContent = mUrlFetcher.getWebContentFromUrl(new URL(url),
+                    HTTP_CONTENT_SIZE_LIMIT_IN_BYTES, HTTP_CONNECTION_TIMEOUT_MILLIS);
+        } catch (IOException e) {
+            return Result.create(statements, DO_NOT_CACHE_RESULT);
+        }
+
+        try {
+            ParsedStatement result = StatementParser
+                    .parseStatementList(webContent.getContent(), source);
+            statements.addAll(result.getStatements());
+            for (String delegate : result.getDelegates()) {
+                statements.addAll(
+                        retrieveStatementFromUrl(delegate, maxIncludeLevel - 1, source)
+                                .getStatements());
+            }
+            return Result.create(statements, webContent.getExpireTimeMillis());
+        } catch (JSONException e) {
+            return Result.create(statements, DO_NOT_CACHE_RESULT);
+        }
+    }
+
+    private Result retrieveFromWeb(WebAsset asset)
+            throws AssociationServiceException {
+        return retrieveStatementFromUrl(computeAssociationJsonUrl(asset), MAX_INCLUDE_LEVEL, asset);
+    }
+
+    private Result retrieveFromAndroid(AndroidAppAsset asset) throws AssociationServiceException {
+        try {
+            List<String> delegates = new ArrayList<String>();
+            List<Statement> statements = new ArrayList<Statement>();
+
+            List<String> certFps = mAndroidFetcher.getCertFingerprints(asset.getPackageName());
+            if (!Utils.hasCommonString(certFps, asset.getCertFingerprints())) {
+                throw new AssociationServiceException(
+                        "Specified certs don't match the installed app.");
+            }
+
+            AndroidAppAsset actualSource = AndroidAppAsset.create(asset.getPackageName(), certFps);
+            for (String statementJson : mAndroidFetcher.getStatements(asset.getPackageName())) {
+                ParsedStatement result =
+                        StatementParser.parseStatement(statementJson, actualSource);
+                statements.addAll(result.getStatements());
+                delegates.addAll(result.getDelegates());
+            }
+
+            for (String delegate : delegates) {
+                statements.addAll(retrieveStatementFromUrl(delegate, MAX_INCLUDE_LEVEL,
+                        actualSource).getStatements());
+            }
+
+            return Result.create(statements, DO_NOT_CACHE_RESULT);
+        } catch (JSONException | NameNotFoundException e) {
+            Log.w(DirectStatementRetriever.class.getSimpleName(), e);
+            return Result.create(Collections.<Statement>emptyList(), DO_NOT_CACHE_RESULT);
+        }
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java b/packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java
new file mode 100644
index 0000000..9446e66
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/ParsedStatement.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import java.util.List;
+
+/**
+ * A class that stores a list of statement and/or a list of delegate url.
+ */
+/* package private */ final class ParsedStatement {
+
+    private final List<Statement> mStatements;
+    private final List<String> mDelegates;
+
+    public ParsedStatement(List<Statement> statements, List<String> delegates) {
+        this.mStatements = statements;
+        this.mDelegates = delegates;
+    }
+
+    public List<Statement> getStatements() {
+        return mStatements;
+    }
+
+    public List<String> getDelegates() {
+        return mDelegates;
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Relation.java b/packages/StatementService/src/com/android/statementservice/retriever/Relation.java
new file mode 100644
index 0000000..91218c6
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Relation.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import android.annotation.NonNull;
+
+import java.util.regex.Pattern;
+
+/**
+ * An immutable value type representing a statement relation with "kind" and "detail".
+ *
+ * <p> The set of kinds is enumerated by the API: <ul> <li> <b>delegate_permission</b>: The detail
+ * field specifies which permission to delegate. A statement involving this relation does not
+ * constitute a requirement to do the delegation, just a permission to do so. </ul>
+ *
+ * <p> We may add other kinds in the future.
+ *
+ * <p> The detail field is a lowercase alphanumeric string with underscores and periods allowed
+ * (matching the regex [a-z0-9_.]+), but otherwise unstructured. It is also possible to specify '*'
+ * (the wildcard character) as the detail if the relation applies to any detail in the specified
+ * kind.
+ */
+public final class Relation {
+
+    private static final Pattern KIND_PATTERN = Pattern.compile("^[a-z0-9_.]+$");
+    private static final Pattern DETAIL_PATTERN = Pattern.compile("^([a-z0-9_.]+|[*])$");
+
+    private static final String MATCH_ALL_DETAILS = "*";
+
+    private final String mKind;
+    private final String mDetail;
+
+    private Relation(String kind, String detail) {
+        mKind = kind;
+        mDetail = detail;
+    }
+
+    /**
+     * Returns the relation's kind.
+     */
+    @NonNull
+    public String getKind() {
+        return mKind;
+    }
+
+    /**
+     * Returns the relation's detail.
+     */
+    @NonNull
+    public String getDetail() {
+        return mDetail;
+    }
+
+    /**
+     * Creates a new Relation object for the specified {@code kind} and {@code detail}.
+     *
+     * @throws AssociationServiceException if {@code kind} or {@code detail} is not well formatted.
+     */
+    public static Relation create(@NonNull String kind, @NonNull String detail)
+            throws AssociationServiceException {
+        if (!KIND_PATTERN.matcher(kind).matches() || !DETAIL_PATTERN.matcher(detail).matches()) {
+            throw new AssociationServiceException("Relation not well formatted.");
+        }
+        return new Relation(kind, detail);
+    }
+
+    /**
+     * Creates a new Relation object from its string representation.
+     *
+     * @throws AssociationServiceException if the relation is not well formatted.
+     */
+    public static Relation create(@NonNull String relation) throws AssociationServiceException {
+        String[] r = relation.split("/", 2);
+        if (r.length != 2) {
+            throw new AssociationServiceException("Relation not well formatted.");
+        }
+        return create(r[0], r[1]);
+    }
+
+    /**
+     * Returns true if {@code relation} has the same kind and detail. If {@code
+     * relation.getDetail()} is wildcard (*) then returns true if the kind is the same.
+     */
+    public boolean matches(Relation relation) {
+        return getKind().equals(relation.getKind()) && (getDetail().equals(MATCH_ALL_DETAILS)
+                || getDetail().equals(relation.getDetail()));
+    }
+
+    /**
+     * Returns a string representation of this relation.
+     */
+    @Override
+    public String toString() {
+        StringBuilder relation = new StringBuilder();
+        relation.append(getKind());
+        relation.append("/");
+        relation.append(getDetail());
+        return relation.toString();
+    }
+
+    // equals() and hashCode() are generated by Android Studio.
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Relation relation = (Relation) o;
+
+        if (mDetail != null ? !mDetail.equals(relation.mDetail) : relation.mDetail != null) {
+            return false;
+        }
+        if (mKind != null ? !mKind.equals(relation.mKind) : relation.mKind != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mKind != null ? mKind.hashCode() : 0;
+        result = 31 * result + (mDetail != null ? mDetail.hashCode() : 0);
+        return result;
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
new file mode 100644
index 0000000..f83edaf
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import android.annotation.NonNull;
+
+/**
+ * An immutable value type representing a statement, consisting of a source, target, and relation.
+ * This reflects an assertion that the relation holds for the source, target pair. For example, if a
+ * web site has the following in its associations.json file:
+ *
+ * <pre>
+ * {
+ * "relation": ["delegate_permission/common.handle_all_urls"],
+ * "target"  : {"namespace": "android_app", "package_name": "com.example.app",
+ *              "sha256_cert_fingerprints": ["00:11:22:33"] }
+ * }
+ * </pre>
+ *
+ * Then invoking {@link AbstractStatementRetriever#retrieveStatements(AbstractAsset)} will return a
+ * {@link Statement} with {@link #getSource} equal to the input parameter, {@link #getRelation}
+ * equal to
+ *
+ * <pre>Relation.create("delegate_permission", "common.get_login_creds");</pre>
+ *
+ * and with {@link #getTarget} equal to
+ *
+ * <pre>AbstractAsset.create("{\"namespace\" : \"android_app\","
+ *                           + "\"package_name\": \"com.example.app\"}"
+ *                           + "\"sha256_cert_fingerprints\": \"[\"00:11:22:33\"]\"}");
+ * </pre>
+ */
+public final class Statement {
+
+    private final AbstractAsset mTarget;
+    private final Relation mRelation;
+    private final AbstractAsset mSource;
+
+    private Statement(AbstractAsset source, AbstractAsset target, Relation relation) {
+        mSource = source;
+        mTarget = target;
+        mRelation = relation;
+    }
+
+    /**
+     * Returns the source asset of the statement.
+     */
+    @NonNull
+    public AbstractAsset getSource() {
+        return mSource;
+    }
+
+    /**
+     * Returns the target asset of the statement.
+     */
+    @NonNull
+    public AbstractAsset getTarget() {
+        return mTarget;
+    }
+
+    /**
+     * Returns the relation of the statement.
+     */
+    @NonNull
+    public Relation getRelation() {
+        return mRelation;
+    }
+
+    /**
+     * Creates a new Statement object for the specified target asset and relation. For example:
+     * <pre>
+     *   Asset asset = Asset.Factory.create(
+     *       "{\"namespace\" : \"web\",\"site\": \"https://www.test.com\"}");
+     *   Relation relation = Relation.create("delegate_permission", "common.get_login_creds");
+     *   Statement statement = Statement.create(asset, relation);
+     * </pre>
+     */
+    public static Statement create(@NonNull AbstractAsset source, @NonNull AbstractAsset target,
+                                   @NonNull Relation relation) {
+        return new Statement(source, target, relation);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Statement statement = (Statement) o;
+
+        if (!mRelation.equals(statement.mRelation)) {
+            return false;
+        }
+        if (!mTarget.equals(statement.mTarget)) {
+            return false;
+        }
+        if (!mSource.equals(statement.mSource)) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mTarget.hashCode();
+        result = 31 * result + mRelation.hashCode();
+        result = 31 * result + mSource.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder statement = new StringBuilder();
+        statement.append("Statement: ");
+        statement.append(mSource);
+        statement.append(", ");
+        statement.append(mTarget);
+        statement.append(", ");
+        statement.append(mRelation);
+        return statement.toString();
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java b/packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java
new file mode 100644
index 0000000..bcd91bd
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/StatementParser.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class that parses JSON-formatted statements.
+ */
+/* package private */ final class StatementParser {
+
+    /**
+     * Parses a JSON array of statements.
+     */
+    static ParsedStatement parseStatementList(String statementList, AbstractAsset source)
+            throws JSONException, AssociationServiceException {
+        List<Statement> statements = new ArrayList<Statement>();
+        List<String> delegates = new ArrayList<String>();
+
+        JSONArray statementsJson = new JSONArray(statementList);
+        for (int i = 0; i < statementsJson.length(); i++) {
+            ParsedStatement result = parseStatement(statementsJson.getString(i), source);
+            statements.addAll(result.getStatements());
+            delegates.addAll(result.getDelegates());
+        }
+
+        return new ParsedStatement(statements, delegates);
+    }
+
+    /**
+     * Parses a single JSON statement.
+     */
+    static ParsedStatement parseStatement(String statementString, AbstractAsset source)
+            throws JSONException, AssociationServiceException {
+        List<Statement> statements = new ArrayList<Statement>();
+        List<String> delegates = new ArrayList<String>();
+        JSONObject statement = new JSONObject(statementString);
+        if (statement.optString(Utils.DELEGATE_FIELD_DELEGATE, null) != null) {
+            delegates.add(statement.optString(Utils.DELEGATE_FIELD_DELEGATE));
+        } else {
+            AbstractAsset target = AssetFactory
+                    .create(statement.getString(Utils.ASSET_DESCRIPTOR_FIELD_TARGET));
+            JSONArray relations = statement.getJSONArray(
+                    Utils.ASSET_DESCRIPTOR_FIELD_RELATION);
+            for (int i = 0; i < relations.length(); i++) {
+                statements.add(Statement
+                        .create(source, target, Relation.create(relations.getString(i))));
+            }
+        }
+
+        return new ParsedStatement(statements, delegates);
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
new file mode 100644
index 0000000..4828ff9
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import com.android.volley.Cache;
+import com.android.volley.NetworkResponse;
+import com.android.volley.toolbox.HttpHeaderParser;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Helper class for fetching HTTP or HTTPS URL.
+ *
+ * Visible for testing.
+ *
+ * @hide
+ */
+public class URLFetcher {
+
+    private static final long DO_NOT_CACHE_RESULT = 0L;
+    private static final int INPUT_BUFFER_SIZE_IN_BYTES = 1024;
+
+    /**
+     * Fetches the specified url and returns the content and ttl.
+     *
+     * @throws IOException if it can't retrieve the content due to a network problem.
+     * @throws AssociationServiceException if the URL scheme is not http or https or the content
+     * length exceeds {code fileSizeLimit}.
+     */
+    public WebContent getWebContentFromUrl(URL url, long fileSizeLimit, int connectionTimeoutMillis)
+            throws AssociationServiceException, IOException {
+        final String scheme = url.getProtocol().toLowerCase(Locale.US);
+        if (!scheme.equals("http") && !scheme.equals("https")) {
+            throw new IllegalArgumentException("The url protocol should be on http or https.");
+        }
+
+        HttpURLConnection connection;
+        connection = (HttpURLConnection) url.openConnection();
+        connection.setInstanceFollowRedirects(true);
+        connection.setConnectTimeout(connectionTimeoutMillis);
+        connection.setReadTimeout(connectionTimeoutMillis);
+        connection.setUseCaches(true);
+        connection.addRequestProperty("Cache-Control", "max-stale=60");
+
+        if (connection.getContentLength() > fileSizeLimit) {
+            throw new AssociationServiceException("The content size of the url is larger than "
+                    + fileSizeLimit);
+        }
+
+        Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(connection.getHeaderFields());
+
+        try {
+            return new WebContent(inputStreamToString(
+                    connection.getInputStream(), connection.getContentLength(), fileSizeLimit),
+                expireTimeMillis);
+        } finally {
+            connection.disconnect();
+        }
+    }
+
+    /**
+     * Visible for testing.
+     * @hide
+     */
+    public static String inputStreamToString(InputStream inputStream, int length, long sizeLimit)
+            throws IOException, AssociationServiceException {
+        if (length < 0) {
+            length = 0;
+        }
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(length);
+        BufferedInputStream bis = new BufferedInputStream(inputStream);
+        byte[] buffer = new byte[INPUT_BUFFER_SIZE_IN_BYTES];
+        int len = 0;
+        while ((len = bis.read(buffer)) != -1) {
+            baos.write(buffer, 0, len);
+            if (baos.size() > sizeLimit) {
+                throw new AssociationServiceException("The content size of the url is larger than "
+                        + sizeLimit);
+            }
+        }
+        return baos.toString("UTF-8");
+    }
+
+    /**
+     * Parses the HTTP headers to compute the ttl.
+     *
+     * @param headers a map that map the header key to the header values. Can be null.
+     * @return the ttl in millisecond or null if the ttl is not specified in the header.
+     */
+    private Long getExpirationTimeMillisFromHTTPHeader(Map<String, List<String>> headers) {
+        if (headers == null) {
+            return null;
+        }
+        Map<String, String> joinedHeaders = joinHttpHeaders(headers);
+
+        NetworkResponse response = new NetworkResponse(null, joinedHeaders);
+        Cache.Entry cachePolicy = HttpHeaderParser.parseCacheHeaders(response);
+
+        if (cachePolicy == null) {
+            // Cache is disabled, set the expire time to 0.
+            return DO_NOT_CACHE_RESULT;
+        } else if (cachePolicy.ttl == 0) {
+            // Cache policy is not specified, set the expire time to 0.
+            return DO_NOT_CACHE_RESULT;
+        } else {
+            // cachePolicy.ttl is actually the expire timestamp in millisecond.
+            return cachePolicy.ttl;
+        }
+    }
+
+    /**
+     * Converts an HTTP header map of the format provided by {@linkHttpUrlConnection} to a map of
+     * the format accepted by {@link HttpHeaderParser}. It does this by joining all the entries for
+     * a given header key with ", ".
+     */
+    private Map<String, String> joinHttpHeaders(Map<String, List<String>> headers) {
+        Map<String, String> joinedHeaders = new HashMap<String, String>();
+        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+            List<String> values = entry.getValue();
+            if (values.size() == 1) {
+                joinedHeaders.put(entry.getKey(), values.get(0));
+            } else {
+                joinedHeaders.put(entry.getKey(), Utils.joinStrings(", ", values));
+            }
+        }
+        return joinedHeaders;
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Utils.java b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
new file mode 100644
index 0000000..44af864
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Utils.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.statementservice.retriever;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.Signature;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Utility library for computing certificate fingerprints. Also includes fields name used by
+ * Statement JSON string.
+ */
+public final class Utils {
+
+    private Utils() {}
+
+    /**
+     * Field name for namespace.
+     */
+    public static final String NAMESPACE_FIELD = "namespace";
+
+    /**
+     * Supported asset namespaces.
+     */
+    public static final String NAMESPACE_WEB = "web";
+    public static final String NAMESPACE_ANDROID_APP = "android_app";
+
+    /**
+     * Field names in a web asset descriptor.
+     */
+    public static final String WEB_ASSET_FIELD_SITE = "site";
+
+    /**
+     * Field names in a Android app asset descriptor.
+     */
+    public static final String ANDROID_APP_ASSET_FIELD_PACKAGE_NAME = "package_name";
+    public static final String ANDROID_APP_ASSET_FIELD_CERT_FPS = "sha256_cert_fingerprints";
+
+    /**
+     * Field names in a statement.
+     */
+    public static final String ASSET_DESCRIPTOR_FIELD_RELATION = "relation";
+    public static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target";
+    public static final String DELEGATE_FIELD_DELEGATE = "delegate";
+
+    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+            'A', 'B', 'C', 'D', 'E', 'F' };
+
+    /**
+     * Joins a list of strings, by placing separator between each string. For example,
+     * {@code joinStrings("; ", Arrays.asList(new String[]{"a", "b", "c"}))} returns
+     * "{@code a; b; c}".
+     */
+    public static String joinStrings(String separator, List<String> strings) {
+        switch(strings.size()) {
+            case 0:
+                return "";
+            case 1:
+                return strings.get(0);
+            default:
+                StringBuilder joiner = new StringBuilder();
+                boolean first = true;
+                for (String field : strings) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        joiner.append(separator);
+                    }
+                    joiner.append(field);
+                }
+                return joiner.toString();
+        }
+    }
+
+    /**
+     * Returns the normalized sha-256 fingerprints of a given package according to the Android
+     * package manager.
+     */
+    public static List<String> getCertFingerprintsFromPackageManager(String packageName,
+            Context context) throws NameNotFoundException {
+        Signature[] signatures = context.getPackageManager().getPackageInfo(packageName,
+                PackageManager.GET_SIGNATURES).signatures;
+        ArrayList<String> result = new ArrayList<String>(signatures.length);
+        for (Signature sig : signatures) {
+            result.add(computeNormalizedSha256Fingerprint(sig.toByteArray()));
+        }
+        return result;
+    }
+
+    /**
+     * Computes the hash of the byte array using the specified algorithm, returning a hex string
+     * with a colon between each byte.
+     */
+    public static String computeNormalizedSha256Fingerprint(byte[] signature) {
+        MessageDigest digester;
+        try {
+            digester = MessageDigest.getInstance("SHA-256");
+        } catch (NoSuchAlgorithmException e) {
+            throw new AssertionError("No SHA-256 implementation found.");
+        }
+        digester.update(signature);
+        return byteArrayToHexString(digester.digest());
+    }
+
+    /**
+     * Returns true if there is at least one common string between the two lists of string.
+     */
+    public static boolean hasCommonString(List<String> list1, List<String> list2) {
+        HashSet<String> set2 = new HashSet<>(list2);
+        for (String string : list1) {
+            if (set2.contains(string)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Converts the byte array to an lowercase hexadecimal digits String with a colon character (:)
+     * between each byte.
+     */
+    private static String byteArrayToHexString(byte[] array) {
+        if (array.length == 0) {
+          return "";
+        }
+        char[] buf = new char[array.length * 3 - 1];
+
+        int bufIndex = 0;
+        for (int i = 0; i < array.length; i++) {
+            byte b = array[i];
+            if (i > 0) {
+                buf[bufIndex++] = ':';
+            }
+            buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
+            buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
+        }
+        return new String(buf);
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
new file mode 100644
index 0000000..ca9e62d
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/WebAsset.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+import org.json.JSONObject;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Locale;
+
+/**
+ * Immutable value type that names a web asset.
+ *
+ * <p>A web asset can be named by its protocol, domain, and port using this JSON string:
+ *     { "namespace": "web",
+ *       "site": "[protocol]://[fully-qualified domain]{:[optional port]}" }
+ *
+ * <p>For example, a website hosted on a https server at www.test.com can be named using
+ *     { "namespace": "web",
+ *       "site": "https://www.test.com" }
+ *
+ * <p>The only protocol supported now are https and http. If the optional port is not specified,
+ * the default for each protocol will be used (i.e. 80 for http and 443 for https).
+ */
+/* package private */ final class WebAsset extends AbstractAsset {
+
+    private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set.";
+
+    private final URL mUrl;
+
+    private WebAsset(URL url) {
+        int port = url.getPort() != -1 ? url.getPort() : url.getDefaultPort();
+        try {
+            mUrl = new URL(url.getProtocol().toLowerCase(), url.getHost().toLowerCase(), port, "");
+        } catch (MalformedURLException e) {
+            throw new AssertionError(
+                    "Url should always be validated before calling the constructor.");
+        }
+    }
+
+    public String getDomain() {
+        return mUrl.getHost();
+    }
+
+    public String getPath() {
+        return mUrl.getPath();
+    }
+
+    public String getScheme() {
+        return mUrl.getProtocol();
+    }
+
+    public int getPort() {
+        return mUrl.getPort();
+    }
+
+    @Override
+    public String toJson() {
+        AssetJsonWriter writer = new AssetJsonWriter();
+
+        writer.writeFieldLower(Utils.NAMESPACE_FIELD, Utils.NAMESPACE_WEB);
+        writer.writeFieldLower(Utils.WEB_ASSET_FIELD_SITE, mUrl.toExternalForm());
+
+        return writer.closeAndGetString();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder asset = new StringBuilder();
+        asset.append("WebAsset: ");
+        asset.append(toJson());
+        return asset.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof WebAsset)) {
+            return false;
+        }
+
+        return ((WebAsset) o).toJson().equals(toJson());
+    }
+
+    @Override
+    public int hashCode() {
+        return toJson().hashCode();
+    }
+
+    @Override
+    public int lookupKey() {
+        return toJson().hashCode();
+    }
+
+    /**
+     * Checks that the input is a valid web asset.
+     *
+     * @throws AssociationServiceException if the asset is not well formatted.
+     */
+    protected static WebAsset create(JSONObject asset)
+            throws AssociationServiceException {
+        if (asset.optString(Utils.WEB_ASSET_FIELD_SITE).equals("")) {
+            throw new AssociationServiceException(String.format(MISSING_FIELD_FORMAT_STRING,
+                    Utils.WEB_ASSET_FIELD_SITE));
+        }
+
+        URL url;
+        try {
+            url = new URL(asset.optString(Utils.WEB_ASSET_FIELD_SITE));
+        } catch (MalformedURLException e) {
+            throw new AssociationServiceException("Url is not well formatted.", e);
+        }
+
+        String scheme = url.getProtocol().toLowerCase(Locale.US);
+        if (!scheme.equals("https") && !scheme.equals("http")) {
+            throw new AssociationServiceException("Expected scheme to be http or https.");
+        }
+
+        if (url.getUserInfo() != null) {
+            throw new AssociationServiceException("The url should not contain user info.");
+        }
+
+        String path = url.getFile(); // This is url.getPath() + url.getQuery().
+        if (!path.equals("/") && !path.equals("")) {
+            throw new AssociationServiceException(
+                    "Site should only have scheme, domain, and port.");
+        }
+
+        return new WebAsset(url);
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebAssetMatcher.java b/packages/StatementService/src/com/android/statementservice/retriever/WebAssetMatcher.java
new file mode 100644
index 0000000..8a1078b
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/WebAssetMatcher.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+/**
+ * Match assets that have the same 'site' field.
+ */
+/* package private */ final class WebAssetMatcher extends AbstractAssetMatcher {
+
+    private final WebAsset mQuery;
+
+    public WebAssetMatcher(WebAsset query) {
+        mQuery = query;
+    }
+
+    @Override
+    public boolean matches(AbstractAsset asset) {
+        if (asset instanceof WebAsset) {
+            WebAsset webAsset = (WebAsset) asset;
+            return webAsset.toJson().equals(mQuery.toJson());
+        }
+        return false;
+    }
+
+    @Override
+    public int getMatchedLookupKey() {
+        return mQuery.lookupKey();
+    }
+}
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java b/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java
new file mode 100644
index 0000000..86a635c
--- /dev/null
+++ b/packages/StatementService/src/com/android/statementservice/retriever/WebContent.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statementservice.retriever;
+
+/**
+ * An immutable value type representing the response from a web server.
+ *
+ * Visible for testing.
+ *
+ * @hide
+ */
+public final class WebContent {
+
+    private final String mContent;
+    private final Long mExpireTimeMillis;
+
+    public WebContent(String content, Long expireTimeMillis) {
+        mContent = content;
+        mExpireTimeMillis = expireTimeMillis;
+    }
+
+    /**
+     * Returns the expiration time of the content as specified in the HTTP header.
+     */
+    public Long getExpireTimeMillis() {
+        return mExpireTimeMillis;
+    }
+
+    /**
+     * Returns content of the HTTP message body.
+     */
+    public String getContent() {
+        return mContent;
+    }
+}
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 47ef42a..51fea2a 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -20,6 +20,11 @@
     $(LOCAL_PATH)/res
 LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.keyguard
 
+ifneq ($(SYSTEM_UI_INCREMENTAL_BUILDS),)
+    LOCAL_PROGUARD_ENABLED := disabled
+    LOCAL_JACK_ENABLED := incremental
+endif
+
 include frameworks/base/packages/SettingsLib/common.mk
 
 include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7a58c87..012c84c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -120,6 +120,9 @@
     <!-- Screen Capturing -->
     <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
 
+    <!-- Assist -->
+    <uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
@@ -178,15 +181,6 @@
                 android:excludeFromRecents="true">
         </activity>
 
-        <receiver
-            android:name=".recent.RecentsPreloadReceiver"
-            android:exported="false">
-            <intent-filter>
-                <action android:name="com.android.systemui.recent.action.PRELOAD" />
-                <action android:name="com.android.systemui.recent.action.CANCEL_PRELOAD" />
-            </intent-filter>
-        </receiver>
-
         <!-- Alternate Recents -->
         <activity android:name=".recents.RecentsActivity"
                   android:label="@string/accessibility_desc_recent_apps"
@@ -195,6 +189,7 @@
                   android:excludeFromRecents="true"
                   android:stateNotNeeded="true"
                   android:resumeWhilePausing="true"
+                  android:screenOrientation="behind"
                   android:theme="@style/config_recents_activity_theme">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
diff --git a/packages/SystemUI/res/anim/ic_volume_collapse_chevron_02_animation.xml b/packages/SystemUI/res/anim/ic_volume_collapse_chevron_02_animation.xml
new file mode 100644
index 0000000..443f2a6
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_volume_collapse_chevron_02_animation.xml
@@ -0,0 +1,25 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="250"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:pathData="M 12.0,9.0 c 0.0,0.66667 0.0,5.0 0.0,6.0"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY" />
+
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/ic_volume_collapse_rectangle_1_animation.xml b/packages/SystemUI/res/anim/ic_volume_collapse_rectangle_1_animation.xml
new file mode 100644
index 0000000..d82f670
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_volume_collapse_rectangle_1_animation.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="200"
+        android:interpolator="@interpolator/ic_volume_collapse_animation_interpolator_0"
+        android:propertyName="rotation"
+        android:valueFrom="45.0"
+        android:valueTo="-45.0"
+        android:valueType="floatType" />
+
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/ic_volume_collapse_rectangle_2_animation.xml b/packages/SystemUI/res/anim/ic_volume_collapse_rectangle_2_animation.xml
new file mode 100644
index 0000000..0bc66bd
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_volume_collapse_rectangle_2_animation.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="200"
+        android:interpolator="@interpolator/ic_volume_collapse_animation_interpolator_0"
+        android:propertyName="rotation"
+        android:valueFrom="-45.0"
+        android:valueTo="45.0"
+        android:valueType="floatType" />
+
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/ic_volume_expand_chevron_01_animation.xml b/packages/SystemUI/res/anim/ic_volume_expand_chevron_01_animation.xml
new file mode 100644
index 0000000..e43e645
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_volume_expand_chevron_01_animation.xml
@@ -0,0 +1,25 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="250"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:pathData="M 12.0,15.0 c 0.0,-1.0 0.0,-5.33333 0.0,-6.0"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY" />
+
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/ic_volume_expand_rectangle_3_animation.xml b/packages/SystemUI/res/anim/ic_volume_expand_rectangle_3_animation.xml
new file mode 100644
index 0000000..9b575d8
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_volume_expand_rectangle_3_animation.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="200"
+        android:interpolator="@interpolator/ic_volume_expand_animation_interpolator_0"
+        android:propertyName="rotation"
+        android:valueFrom="45.0"
+        android:valueTo="-45.0"
+        android:valueType="floatType" />
+
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/anim/ic_volume_expand_rectangle_4_animation.xml b/packages/SystemUI/res/anim/ic_volume_expand_rectangle_4_animation.xml
new file mode 100644
index 0000000..6ae0fef
--- /dev/null
+++ b/packages/SystemUI/res/anim/ic_volume_expand_rectangle_4_animation.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<set xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <objectAnimator
+        android:duration="200"
+        android:interpolator="@interpolator/ic_volume_expand_animation_interpolator_0"
+        android:propertyName="rotation"
+        android:valueFrom="-45.0"
+        android:valueTo="45.0"
+        android:valueType="floatType" />
+
+</set>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/assist_orb_navbar_scrim.xml b/packages/SystemUI/res/drawable/assist_orb_navbar_scrim.xml
new file mode 100644
index 0000000..52ed76d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/assist_orb_navbar_scrim.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+            android:type="linear"
+            android:angle="90"
+            android:startColor="#33000000"
+            android:endColor="#00000000" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/search_panel_scrim.xml b/packages/SystemUI/res/drawable/assist_orb_scrim.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/search_panel_scrim.xml
rename to packages/SystemUI/res/drawable/assist_orb_scrim.xml
diff --git a/packages/SystemUI/res/drawable/btn_borderless_rect.xml b/packages/SystemUI/res/drawable/btn_borderless_rect.xml
index d640141..c0a89f9 100644
--- a/packages/SystemUI/res/drawable/btn_borderless_rect.xml
+++ b/packages/SystemUI/res/drawable/btn_borderless_rect.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!--
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,13 +13,15 @@
      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:color="?android:attr/colorControlHighlight">
+    android:color="?android:attr/colorControlHighlight" >
+
     <item android:id="@android:id/mask">
         <shape>
             <corners android:radius="@dimen/borderless_button_radius" />
+
             <solid android:color="@android:color/white" />
         </shape>
     </item>
+
 </ripple>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_dnd.xml b/packages/SystemUI/res/drawable/ic_dnd.xml
new file mode 100644
index 0000000..17ecf21
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_dnd.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M24.0,4.0C12.95,4.0 4.0,12.95 4.0,24.0s8.95,20.0 20.0,20.0 20.0,-8.95 20.0,-20.0S35.05,4.0 24.0,4.0zm10.0,22.0L14.0,26.0l0.0,-4.0l20.0,0.0l0.0,4.0z" />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint.xml b/packages/SystemUI/res/drawable/ic_fingerprint.xml
new file mode 100644
index 0000000..ee2cf03
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_fingerprint.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <path
+        android:fillColor="#80ffffff"
+        android:pathData="M23.7,5.9c-0.1,0.0 -0.2,0.0 -0.3,-0.1C21.0,4.5 18.6,3.9 16.0,3.9c-2.5,0.0 -4.6,0.6 -6.9,1.9C8.8,6.0 8.3,5.9 8.1,5.5C7.9,5.2 8.0,4.7 8.4,4.5c2.5,-1.4 4.9,-2.1 7.7,-2.1c2.8,0.0 5.4,0.7 8.0,2.1c0.4,0.2 0.5,0.6 0.3,1.0C24.2,5.7 24.0,5.9 23.7,5.9z"/>
+    <path
+        android:fillColor="#80ffffff"
+        android:pathData="M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z"/>
+    <path
+        android:fillColor="#80ffffff"
+        android:pathData="M13.3,29.6c-0.2,0.0 -0.4,-0.1 -0.5,-0.2c-1.1,-1.2 -1.7,-2.0 -2.6,-3.6c-0.9,-1.7 -1.4,-3.7 -1.4,-5.9c0.0,-4.1 3.3,-7.4 7.4,-7.4c4.1,0.0 7.4,3.3 7.4,7.4c0.0,0.4 -0.3,0.7 -0.7,0.7s-0.7,-0.3 -0.7,-0.7c0.0,-3.3 -2.7,-5.9 -5.9,-5.9c-3.3,0.0 -5.9,2.7 -5.9,5.9c0.0,2.0 0.4,3.8 1.2,5.2c0.8,1.6 1.4,2.2 2.4,3.3c0.3,0.3 0.3,0.8 0.0,1.0C13.7,29.5 13.5,29.6 13.3,29.6z"/>
+    <path
+        android:fillColor="#80ffffff"
+        android:pathData="M22.6,27.1c-1.6,0.0 -2.9,-0.4 -4.1,-1.2c-1.9,-1.4 -3.1,-3.6 -3.1,-6.0c0.0,-0.4 0.3,-0.7 0.7,-0.7s0.7,0.3 0.7,0.7c0.0,1.9 0.9,3.7 2.5,4.8c0.9,0.6 1.9,1.0 3.2,1.0c0.3,0.0 0.8,0.0 1.3,-0.1c0.4,-0.1 0.8,0.2 0.8,0.6c0.1,0.4 -0.2,0.8 -0.6,0.8C23.4,27.1 22.8,27.1 22.6,27.1z"/>
+    <path
+        android:fillColor="#80ffffff"
+        android:pathData="M20.0,29.9c-0.1,0.0 -0.1,0.0 -0.2,0.0c-2.1,-0.6 -3.4,-1.4 -4.8,-2.9c-1.8,-1.9 -2.8,-4.4 -2.8,-7.1c0.0,-2.2 1.8,-4.1 4.1,-4.1c2.2,0.0 4.1,1.8 4.1,4.1c0.0,1.4 1.2,2.6 2.6,2.6c1.4,0.0 2.6,-1.2 2.6,-2.6c0.0,-5.1 -4.2,-9.3 -9.3,-9.3c-3.6,0.0 -6.9,2.1 -8.4,5.4C7.3,17.1 7.0,18.4 7.0,19.8c0.0,1.1 0.1,2.7 0.9,4.9c0.1,0.4 -0.1,0.8 -0.4,0.9c-0.4,0.1 -0.8,-0.1 -0.9,-0.4c-0.6,-1.8 -0.9,-3.6 -0.9,-5.4c0.0,-1.6 0.3,-3.1 0.9,-4.4c1.7,-3.8 5.6,-6.3 9.8,-6.3c5.9,0.0 10.7,4.8 10.7,10.7c0.0,2.2 -1.8,4.1 -4.1,4.1s-4.0,-1.8 -4.0,-4.1c0.0,-1.4 -1.2,-2.6 -2.6,-2.6c-1.4,0.0 -2.6,1.2 -2.6,2.6c0.0,2.3 0.9,4.5 2.4,6.1c1.2,1.3 2.4,2.0 4.2,2.5c0.4,0.1 0.6,0.5 0.5,0.9C20.6,29.7 20.3,29.9 20.0,29.9z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_fingerprint_error.xml b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
new file mode 100644
index 0000000..11e83a1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_fingerprint_error.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="32.0dp"
+        android:height="32.0dp"
+        android:viewportWidth="32.0"
+        android:viewportHeight="32.0">
+    <path
+        android:fillColor="@color/system_warning_color"
+        android:pathData="M15.99,2.5C8.53,2.5 2.5,8.54 2.5,16.0s6.03,13.5 13.49,13.5S29.5,23.46 29.5,16.0S23.45,2.5 15.99,2.5zM16.0,26.8c-5.97,0.0 -10.8,-4.83 -10.8,-10.8S10.03,5.2 16.0,5.2S26.8,10.03 26.8,16.0S21.97,26.8 16.0,26.8z"/>
+    <path
+        android:fillColor="@color/system_warning_color"
+        android:pathData="M14.65,20.05l2.7,0.0l0.0,2.7l-2.7,0.0z"/>
+    <path
+        android:fillColor="@color/system_warning_color"
+        android:pathData="M14.65,9.25l2.7,0.0l0.0,8.1l-2.7,0.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_minus.xml b/packages/SystemUI/res/drawable/ic_qs_minus.xml
index 4722c9e..6a3410a 100644
--- a/packages/SystemUI/res/drawable/ic_qs_minus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_minus.xml
@@ -1,25 +1,26 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+     Copyright (C) 2015 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
 
-         http://www.apache.org/licenses/LICENSE-2.0
+          http://www.apache.org/licenses/LICENSE-2.0
 
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+    android:height="24.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24.0dp" >
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0L14.0,26.0l0.0,-4.0l20.0,0.0L34.0,26.0z"/>
-</vector>
+        android:pathData="M38.0,26.0L10.0,26.0l0.0,-4.0l28.0,0.0l0.0,4.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_plus.xml b/packages/SystemUI/res/drawable/ic_qs_plus.xml
index 17d74cf..393f51c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_plus.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_plus.xml
@@ -1,25 +1,26 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+     Copyright (C) 2015 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
 
-         http://www.apache.org/licenses/LICENSE-2.0
+          http://www.apache.org/licenses/LICENSE-2.0
 
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+    android:height="24.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24.0dp" >
 
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0s9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0S35.0,4.0 24.0,4.0zM34.0,26.0l-8.0,0.0l0.0,8.0l-4.0,0.0l0.0,-8.0l-8.0,0.0l0.0,-4.0l8.0,0.0l0.0,-8.0l4.0,0.0l0.0,8.0l8.0,0.0L34.0,26.0z"/>
-</vector>
+        android:pathData="M38.0,26.0L26.0,26.0l0.0,12.0l-4.0,0.0L22.0,26.0L10.0,26.0l0.0,-4.0l12.0,0.0L22.0,10.0l4.0,0.0l0.0,12.0l12.0,0.0l0.0,4.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm.xml b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
new file mode 100644
index 0000000..a8ca0d6
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M44.0,11.44l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-28.24,-4.66l-2.57,-3.06 -9.19,7.71 2.57,3.06 9.19,-7.71zm9.24,9.22l-3.0,0.0l0.0,12.0l9.49,5.71 1.51,-2.47 -8.0,-4.74l0.0,-10.5zm-1.01,-8.0c-9.95,0.0 -17.99,8.06 -17.99,18.0s8.04,18.0 17.99,18.0 18.01,-8.06 18.01,-18.0 -8.06,-18.0 -18.01,-18.0zm0.01,32.0c-7.73,0.0 -14.0,-6.27 -14.0,-14.0s6.27,-14.0 14.0,-14.0 14.0,6.27 14.0,14.0 -6.26,14.0 -14.0,14.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
new file mode 100644
index 0000000..8e2f083
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M24.0,12.0c7.73,0.0 14.0,6.27 14.0,14.0 0.0,1.69 -0.31,3.3 -0.86,4.8l3.04,3.04c1.16,-2.37 1.82,-5.03 1.82,-7.84 0.0,-9.94 -8.06,-18.0 -18.01,-18.0 -2.81,0.0 -5.46,0.66 -7.84,1.81l3.05,3.05c1.5,-0.55 3.11,-0.86 4.8,-0.86zm20.0,-0.56l-9.19,-7.71 -2.57,3.06 9.19,7.71 2.57,-3.06zm-38.16,-6.85l-2.55,2.54 2.66,2.66 -2.22,1.86 2.84,2.84 2.22,-1.86 1.6,1.6c-2.73,3.16 -4.39,7.27 -4.39,11.77 0.0,9.94 8.04,18.0 17.99,18.0 4.51,0.0 8.62,-1.67 11.77,-4.4l4.4,4.4 2.54,-2.55 -34.91,-34.91 -1.95,-1.95zm27.1,32.19c-2.43,2.01 -5.54,3.22 -8.94,3.22 -7.73,0.0 -14.0,-6.27 -14.0,-14.0 0.0,-3.4 1.21,-6.51 3.22,-8.94l19.72,19.72zm-16.91,-30.23l-2.84,-2.84 -1.7,1.43 2.84,2.84 1.7,-1.43z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_bt_sco.xml b/packages/SystemUI/res/drawable/ic_volume_bt_sco.xml
new file mode 100644
index 0000000..71df4d3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_bt_sco.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M29.41,19.0L34.0,14.41L34.0,22.0l1.0,0.0l5.71,-5.71 -4.3,-4.29 4.29,-4.29L35.0,2.0l-1.0,0.0l0.0,7.59L29.41,5.0 28.0,6.41 33.59,12.0 28.0,17.59 29.41,19.0zM36.0,5.83l1.88,1.88L36.0,9.59L36.0,5.83zm0.0,8.58l1.88,1.88L36.0,18.17l0.0,-3.76zM40.0,31.0c-2.49,0.0 -4.89,-0.4 -7.14,-1.14 -0.69,-0.22 -1.48,-0.06 -2.0,0.49l-4.4,4.41c-5.67,-2.88 -10.29,-7.51 -13.18,-13.17l4.4,-4.41c0.55,-0.5 0.71,-1.3 0.49,-2.03C17.4,12.9 17.0,10.49 17.0,8.0c0.0,-1.11 -0.89,-2.0 -2.0,-2.0L8.0,6.0c-1.11,0.0 -2.0,0.89 -2.0,2.0 0.0,18.78 15.22,34.0 34.0,34.0 1.11,0.0 2.0,-0.89 2.0,-2.0l0.0,-7.0c0.0,-1.11 -0.89,-2.0 -2.0,-2.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_collapse.xml b/packages/SystemUI/res/drawable/ic_volume_collapse.xml
new file mode 100644
index 0000000..dc6d301
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_collapse.xml
@@ -0,0 +1,62 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="ic_volume_collapse"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+
+    <group
+        android:name="chevron_02"
+        android:rotation="90"
+        android:translateX="12"
+        android:translateY="9" >
+        <group
+            android:name="rectangle_2"
+            android:rotation="-45" >
+            <group
+                android:name="rectangle_2_pivot"
+                android:translateY="4" >
+                <group
+                    android:name="rectangle_path_2_position"
+                    android:translateY="-1" >
+                    <path
+                        android:name="rectangle_path_2"
+                        android:fillColor="#FFFFFFFF"
+                        android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+                </group>
+            </group>
+        </group>
+        <group
+            android:name="rectangle_1"
+            android:rotation="45" >
+            <group
+                android:name="rectangle_1_pivot"
+                android:translateY="-4" >
+                <group
+                    android:name="rectangle_path_1_position"
+                    android:translateY="1" >
+                    <path
+                        android:name="rectangle_path_1"
+                        android:fillColor="#FFFFFFFF"
+                        android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_collapse_animation.xml b/packages/SystemUI/res/drawable/ic_volume_collapse_animation.xml
new file mode 100644
index 0000000..5c482bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_collapse_animation.xml
@@ -0,0 +1,29 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_volume_collapse" >
+
+    <target
+        android:name="chevron_02"
+        android:animation="@anim/ic_volume_collapse_chevron_02_animation" />
+    <target
+        android:name="rectangle_2"
+        android:animation="@anim/ic_volume_collapse_rectangle_2_animation" />
+    <target
+        android:name="rectangle_1"
+        android:animation="@anim/ic_volume_collapse_rectangle_1_animation" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_expand.xml b/packages/SystemUI/res/drawable/ic_volume_expand.xml
new file mode 100644
index 0000000..a60623f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_expand.xml
@@ -0,0 +1,62 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="ic_volume_expand"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:width="24dp" >
+
+    <group
+        android:name="chevron_01"
+        android:rotation="90"
+        android:translateX="12"
+        android:translateY="15" >
+        <group
+            android:name="rectangle_3"
+            android:rotation="45" >
+            <group
+                android:name="rectangle_2_pivot_0"
+                android:translateY="4" >
+                <group
+                    android:name="rectangle_path_3_position"
+                    android:translateY="-1" >
+                    <path
+                        android:name="rectangle_path_3"
+                        android:fillColor="#FFFFFFFF"
+                        android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+                </group>
+            </group>
+        </group>
+        <group
+            android:name="rectangle_4"
+            android:rotation="-45" >
+            <group
+                android:name="rectangle_1_pivot_0"
+                android:translateY="-4" >
+                <group
+                    android:name="rectangle_path_4_position"
+                    android:translateY="1" >
+                    <path
+                        android:name="rectangle_path_4"
+                        android:fillColor="#FFFFFFFF"
+                        android:pathData="M -1.0,-4.0 l 2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-8.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_expand_animation.xml b/packages/SystemUI/res/drawable/ic_volume_expand_animation.xml
new file mode 100644
index 0000000..ae2d7e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_expand_animation.xml
@@ -0,0 +1,29 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_volume_expand" >
+
+    <target
+        android:name="chevron_01"
+        android:animation="@anim/ic_volume_expand_chevron_01_animation" />
+    <target
+        android:name="rectangle_3"
+        android:animation="@anim/ic_volume_expand_rectangle_3_animation" />
+    <target
+        android:name="rectangle_4"
+        android:animation="@anim/ic_volume_expand_rectangle_4_animation" />
+
+</animated-vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_media.xml b/packages/SystemUI/res/drawable/ic_volume_media.xml
new file mode 100644
index 0000000..97089f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_media.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M12.0,3.0l0.0,9.28c-0.47,-0.17 -0.97,-0.28 -1.5,-0.28C8.01,12.0 6.0,14.01 6.0,16.5S8.01,21.0 10.5,21.0c2.31,0.0 4.2,-1.75 4.45,-4.0L15.0,17.0L15.0,6.0l4.0,0.0L19.0,3.0l-7.0,0.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_media_bt.xml b/packages/SystemUI/res/drawable/ic_volume_media_bt.xml
new file mode 100644
index 0000000..3364d9c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_media_bt.xml
@@ -0,0 +1,29 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M17.0,3.0l-7.0,0.0l0.0,9.3C9.5,12.1 9.0,12.0 8.5,12.0C6.0,12.0 4.0,14.0 4.0,16.5S6.0,21.0 8.5,21.0s4.5,-2.3 4.5,-4.5C13.0,14.7 13.0,6.0 13.0,6.0l4.0,0.0L17.0,3.0z"/>
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M23.4,9.9L20.5,7.0L20.0,7.0l0.0,3.8l-2.3,-2.3L17.0,9.2l2.8,2.8L17.0,14.8l0.7,0.7l2.3,-2.3L20.0,17.0l0.5,0.0l2.8,-2.8L21.2,12.0L23.4,9.9zM21.0,8.9l0.9,0.9l-0.9,1.0L21.0,8.9zM21.9,14.2L21.0,15.1l0.0,-1.9L21.9,14.2z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_media_bt_mute.xml b/packages/SystemUI/res/drawable/ic_volume_media_bt_mute.xml
new file mode 100644
index 0000000..39f54f1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_media_bt_mute.xml
@@ -0,0 +1,32 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M13.0,6.0l4.0,0.0L17.0,3.0l-7.0,0.0l0.0,5.6l3.0,3.0C13.0,8.8 13.0,6.0 13.0,6.0z"/>
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M2.1,5.7L8.4,12.0C6.0,12.1 4.0,14.0 4.0,16.5S6.0,21.0 8.5,21.0c2.7,0.0 4.5,-2.3 4.5,-4.3l0.0,-0.1l3.9,3.9l1.3,-1.3L3.4,4.5L2.1,5.7z"/>
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M23.4,9.9L20.5,7.0L20.0,7.0l0.0,3.8l-2.3,-2.3L17.0,9.2l2.8,2.8L17.0,14.8l0.7,0.7l2.3,-2.3L20.0,17.0l0.5,0.0l2.8,-2.8L21.2,12.0L23.4,9.9zM21.0,8.9l0.9,0.9l-0.9,1.0L21.0,8.9zM21.9,14.2L21.0,15.1l0.0,-1.9L21.9,14.2z"/>
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_media_mute.xml b/packages/SystemUI/res/drawable/ic_volume_media_mute.xml
new file mode 100644
index 0000000..beb806c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_media_mute.xml
@@ -0,0 +1,29 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M15.0,6.0l4.0,0.0L19.0,3.0l-7.0,0.0l0.0,5.6l3.0,3.0C15.0,8.8 15.0,6.0 15.0,6.0z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M4.8,3.9L3.5,5.1l6.9,6.9C8.0,12.1 6.0,14.0 6.0,16.5C6.0,19.0 8.0,21.0 10.5,21.0c2.7,0.0 4.5,-2.3 4.5,-4.3c0.0,0.0 0.0,-0.1 0.0,-0.1l4.0,4.0l1.3,-1.3L4.8,3.9z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_remote.xml b/packages/SystemUI/res/drawable/ic_volume_remote.xml
new file mode 100644
index 0000000..b363178
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_remote.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M2.0,36.0l0.0,6.0l6.0,0.0C8.0,38.7 5.3,36.0 2.0,36.0zM2.0,28.0l0.0,4.0c5.5,0.0 10.0,4.5 10.0,10.0l4.0,0.0C16.0,34.3 9.7,28.0 2.0,28.0zM38.0,14.0L10.0,14.0l0.0,3.3c7.9,2.6 14.2,8.8 16.7,16.7L38.0,34.0L38.0,14.0zM2.0,20.0l0.0,4.0c9.9,0.0 18.0,8.1 18.0,18.0l4.0,0.0C24.0,29.8 14.1,20.0 2.0,20.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,6.0l4.0,0.0l0.0,-6.0l36.0,0.0l0.0,28.0L28.0,38.0l0.0,4.0l14.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_remote_mute.xml b/packages/SystemUI/res/drawable/ic_volume_remote_mute.xml
new file mode 100644
index 0000000..5f39ad7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_remote_mute.xml
@@ -0,0 +1,38 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M23.7,21.3l-1.1,-1.0c0.0,0.0 0.0,0.0 0.0,0.0L21.0,18.8l0.0,0.0L5.8,5.0l0.0,0.0L3.6,3.0l0.0,0.0L1.7,1.3L0.3,2.7l1.1,1.0C1.2,4.1 1.0,4.5 1.0,5.0l0.0,3.0l2.0,0.0L3.0,5.2L18.2,19.0L14.0,19.0l0.0,2.0l6.4,0.0l1.9,1.7L23.7,21.3z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M21.0,5.0l0.0,11.1l2.0,1.8L23.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0L6.6,3.0l2.2,2.0L21.0,5.0z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M1.0,18.0l0.0,3.0l3.0,0.0C4.0,19.3 2.7,18.0 1.0,18.0z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M1.0,14.0l0.0,2.0c2.8,0.0 5.0,2.2 5.0,5.0l2.0,0.0C8.0,17.1 4.9,14.0 1.0,14.0z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M1.0,10.0l0.0,2.0c5.0,0.0 9.0,4.0 9.0,9.0l2.0,0.0C12.0,14.9 7.1,10.0 1.0,10.0z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer.xml b/packages/SystemUI/res/drawable/ic_volume_ringer.xml
new file mode 100644
index 0000000..c566d5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        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>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_mute.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_mute.xml
new file mode 100644
index 0000000..0c20361
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_mute.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M23.000000,44.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000l-8.000000,0.000000C19.000000,42.200001 20.799999,44.000000 23.000000,44.000000zM36.000000,21.000000c0.000000,-6.100000 -4.300000,-11.300000 -10.000000,-12.600000L26.000000,7.000000c0.000000,-1.700000 -1.300000,-3.000000 -3.000000,-3.000000c-1.700000,0.000000 -3.000000,1.300000 -3.000000,3.000000l0.000000,1.400000c-1.000000,0.200000 -2.000000,0.600000 -2.900000,1.100000L36.000000,28.400000L36.000000,21.000000zM35.500000,38.000000l4.000000,4.000000l2.500000,-2.500000L8.500000,6.000000L6.000000,8.500000l5.800000,5.800000C10.700000,16.299999 10.000000,18.600000 10.000000,21.000000l0.000000,11.000000l-4.000000,4.000000l0.000000,2.000000L35.500000,38.000000z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
new file mode 100644
index 0000000..38b3234
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        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>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_settings.xml b/packages/SystemUI/res/drawable/ic_volume_settings.xml
new file mode 100644
index 0000000..9f79b5a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_settings.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="20dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="20dp" >
+
+    <path
+        android:fillColor="@color/volume_settings_icon_color"
+        android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_system.xml b/packages/SystemUI/res/drawable/ic_volume_system.xml
new file mode 100644
index 0000000..ccd8e18
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_system.xml
@@ -0,0 +1,32 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M17.7,14.8l-4.5,-2.3c-0.2,-0.1 -0.4,-0.1 -0.5,-0.1l-0.8,0.0l0.0,-6.0c0.0,-0.8 -0.7,-1.5 -1.5,-1.5S8.9,5.6 8.9,6.4l0.0,10.7l-3.4,-0.7c-0.1,0.0 -0.2,0.0 -0.2,0.0c-0.3,0.0 -0.6,0.1 -0.8,0.3l-0.8,0.8l4.9,4.9c0.3,0.3 0.6,0.4 1.1,0.4l6.8,0.0c0.8,0.0 1.3,-0.6 1.4,-1.3l0.8,-5.3c0.0,-0.1 0.0,-0.1 0.0,-0.2C18.6,15.5 18.2,15.0 17.7,14.8z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M14.3,8.8l1.8,0.9c1.5,-2.0 1.4,-4.8 -0.4,-6.6l-1.4,1.4C15.5,5.7 15.5,7.6 14.3,8.8z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M17.9,10.6l1.8,0.9C22.0,8.0 21.6,3.3 18.5,0.3l-1.4,1.4C19.5,4.1 19.8,7.9 17.9,10.6z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_system_mute.xml b/packages/SystemUI/res/drawable/ic_volume_system_mute.xml
new file mode 100644
index 0000000..dfcb655
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_system_mute.xml
@@ -0,0 +1,35 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M14.3,8.8l1.8,0.9c1.5,-2.0 1.4,-4.8 -0.4,-6.6l-1.4,1.4C15.5,5.7 15.5,7.6 14.3,8.8z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M17.9,10.6l1.8,0.9C22.0,8.0 21.6,3.3 18.5,0.3l-1.4,1.4C19.5,4.1 19.8,7.9 17.9,10.6z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M22.0,20.6l-3.5,-2.8l0.0,0.0l-9.6,-7.6l0.0,0.0L3.2,5.7L2.0,7.3l6.9,5.4L8.9,17.0l-3.4,-0.7c-0.1,0.0 -0.2,0.0 -0.2,0.0c-0.3,0.0 -0.6,0.1 -0.8,0.3l-0.8,0.8l4.9,4.9c0.3,0.3 0.6,0.4 1.1,0.4l6.8,0.0c0.8,0.0 1.3,-0.6 1.4,-1.3l0.2,-1.5l2.6,2.1L22.0,20.6z" />
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M11.9,6.4c0.0,-0.8 -0.7,-1.5 -1.5,-1.5S8.9,5.6 8.9,6.4l0.0,1.5l3.0,2.4L11.9,6.4z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_volume_voice.xml b/packages/SystemUI/res/drawable/ic_volume_voice.xml
new file mode 100644
index 0000000..133253e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_volume_voice.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24.0dp"
+    android:viewportHeight="48.0"
+    android:viewportWidth="48.0"
+    android:width="24.0dp" >
+
+    <path
+        android:fillColor="@color/volume_icon_color"
+        android:pathData="M13.25,21.59c2.88,5.66 7.51,10.29 13.18,13.17l4.4,-4.41c0.55,-0.55 1.34,-0.71 2.03,-0.49C35.1,30.6 37.51,31.0 40.0,31.0c1.11,0.0 2.0,0.89 2.0,2.0l0.0,7.0c0.0,1.11 -0.89,2.0 -2.0,2.0C21.22,42.0 6.0,26.78 6.0,8.0c0.0,-1.1 0.9,-2.0 2.0,-2.0l7.0,0.0c1.11,0.0 2.0,0.89 2.0,2.0 0.0,2.4 0.4,4.9 1.14,7.1 0.2,0.6 0.06,1.48 -0.49,2.03l-4.4,4.42z" />
+
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_no_sims.xml b/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
index 8bad226..2229c99 100644
--- a/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_no_sims.xml
@@ -20,6 +20,6 @@
         android:viewportHeight="24.0">
 
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M19.0,5.0c0.0,-1.1 -0.9,-2.0 -2.0,-2.0l-7.0,0.0L7.7,5.3L19.0,16.7L19.0,5.0zM3.7,3.9L2.4,5.2L5.0,7.8L5.0,19.0c0.0,1.1 0.9,2.0 2.0,2.0l10.0,0.0c0.4,0.0 0.7,-0.1 1.0,-0.3l1.9,1.9l1.3,-1.3L3.7,3.9z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
index e1e81fd..643c4f9 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
@@ -20,12 +20,12 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
     <path
         android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:fillColor="?attr/backgroundColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml
index c0dfcf4..e267d25 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_0_fully.xml
@@ -20,6 +20,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
index d1124ee..64781c3 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
@@ -20,15 +20,15 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
index 29eda94..60822f4 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_1_fully.xml
@@ -20,9 +20,9 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M2.0,22.0l20.0,0.0 0.0,-20.0z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
index 537c788..eb2be08 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
@@ -20,15 +20,15 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M13.900000,10.000000l-11.900000,12.000000 11.900000,0.000000z"/>
     <path
         android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:fillColor="?attr/backgroundColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml
index 7d9376e..5e68eed 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_2_fully.xml
@@ -20,9 +20,9 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M14.000000,10.000000l-12.000000,12.000000 12.000000,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
index 09fe33a..22afad0 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
@@ -20,15 +20,15 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,19.900000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,9.900000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M16.700001,7.200000l-14.700001,14.700000 14.700001,0.000000z"/>
     <path
         android:pathData="M17.700001,7.900000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:fillColor="?attr/backgroundColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml
index 8ec5500..599b34a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_3_fully.xml
@@ -20,9 +20,9 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M16.700001,7.300000l-14.700001,14.700000 14.700001,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
index bb98541..d1e866d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
@@ -19,13 +19,14 @@
         android:height="17dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
+
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M2.000000,22.000000l15.700001,0.000000 0.000000,-14.000000 4.299999,0.000000 0.000000,-6.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml
index a468410..b66d89a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_4_fully.xml
@@ -20,6 +20,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M2.000000,22.000000l20.000000,0.000000 0.000000,-20.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_null.xml b/packages/SystemUI/res/drawable/stat_sys_signal_null.xml
index d25fc1c..2b487f9e 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_null.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_null.xml
@@ -20,6 +20,6 @@
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M2.000000,22.000000l20.000000,0.000000L22.000000,2.000000L2.000000,22.000000zM20.000000,20.000000L6.800000,20.000000L20.000000,6.800000L20.000000,20.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
index be930e8..7f1b715e 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
@@ -19,12 +19,12 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M19.000000,8.000000l5.300000,0.000000l1.200000,-1.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml
index b2691f6..60f7eb6 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0_fully.xml
@@ -19,6 +19,6 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
index dde781d..acd89be 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
@@ -19,15 +19,15 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M13.000000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml
index 65931f4..554350d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1_fully.xml
@@ -19,9 +19,9 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M13.100000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.500000,6.500000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M13.100000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000L13.100000,22.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
index 63d9dca..f33b25c 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
@@ -19,15 +19,15 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M19.000000,11.600000c-1.300000,-0.700000 -3.400000,-1.600000 -6.000000,-1.600000c-4.400000,0.000000 -7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,11.600000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml
index 7ba4895..2c2465a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2_fully.xml
@@ -19,9 +19,9 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M13.000000,22.000000l7.600000,-9.400000C20.299999,12.400000 17.400000,10.000000 13.000000,10.000000s-7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
index 7d393b4..09d2e50 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
@@ -19,15 +19,15 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M19.000000,8.600000c-1.600000,-0.700000 -3.600000,-1.300000 -6.000000,-1.300000c-5.300000,0.000000 -8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.600000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml
index e2cde53..7d0f756 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3_fully.xml
@@ -19,9 +19,9 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/fillColor"
         android:pathData="M13.000000,22.000000l9.200000,-11.400000c-0.400000,-0.300000 -3.900000,-3.200000 -9.200000,-3.200000s-8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
index ec8137f..fb1f584 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
@@ -19,12 +19,12 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml
index 9d02980..a7e213f 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4_fully.xml
@@ -19,6 +19,6 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
+        android:fillColor="?attr/singleToneColor"
         android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml
index 95c6531..5169de4 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_null.xml
@@ -19,6 +19,6 @@
         android:viewportWidth="26.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
+        android:fillColor="?attr/backgroundColor"
         android:pathData="M13.000000,2.000000C7.700000,2.000000 3.700000,3.900000 0.400000,6.400000L13.000000,22.000000L25.600000,6.500000C22.299999,4.000000 18.299999,2.000000 13.000000,2.000000zM13.000000,18.600000L3.300000,7.000000l0.000000,0.000000l0.000000,0.000000C6.000000,5.300000 8.700000,4.000000 13.000000,4.000000s7.000000,1.400000 9.700000,3.000000l0.000000,0.000000l0.000000,0.000000L13.000000,18.600000z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/volume_dialog_background.xml b/packages/SystemUI/res/drawable/volume_dialog_background.xml
new file mode 100644
index 0000000..f09c01b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_dialog_background.xml
@@ -0,0 +1,22 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <solid android:color="@color/system_primary_color" />
+
+    <corners android:radius="@dimen/notification_material_rounded_rect_radius" />
+
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/interpolator/ic_volume_collapse_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_volume_collapse_animation_interpolator_0.xml
new file mode 100644
index 0000000..c3930e4
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/ic_volume_collapse_animation_interpolator_0.xml
@@ -0,0 +1,17 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.0001,0.0 0.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_volume_expand_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_volume_expand_animation_interpolator_0.xml
new file mode 100644
index 0000000..c3930e4
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/ic_volume_expand_animation_interpolator_0.xml
@@ -0,0 +1,17 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.0001,0.0 0.0,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout/assist_orb.xml b/packages/SystemUI/res/layout/assist_orb.xml
new file mode 100644
index 0000000..ab0a0a5
--- /dev/null
+++ b/packages/SystemUI/res/layout/assist_orb.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* apps/common/assets/default/default/skins/StatusBar.xml
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Extends FrameLayout -->
+<com.android.systemui.assist.AssistOrbContainer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <com.android.systemui.statusbar.AlphaOptimizedView
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/assist_orb_scrim_height"
+        android:layout_gravity="bottom"
+        android:id="@+id/assist_orb_scrim"
+        android:background="@drawable/assist_orb_scrim"/>
+
+    <com.android.systemui.assist.AssistOrbView
+        android:id="@+id/assist_orb"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <ImageView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:id="@+id/search_logo"/>
+    </com.android.systemui.assist.AssistOrbView>
+
+    <com.android.systemui.statusbar.AlphaOptimizedView
+        android:id="@+id/assist_orb_navbar_scrim"
+        android:layout_height="@dimen/assist_orb_navbar_scrim_height"
+        android:layout_width="match_parent"
+        android:layout_gravity="bottom"
+        android:elevation="50dp"
+        android:outlineProvider="none"
+        android:background="@drawable/assist_orb_navbar_scrim"/>
+
+</com.android.systemui.assist.AssistOrbContainer>
\ 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 01b2713..fca8231 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -68,7 +68,6 @@
         android:layout_gravity="bottom|center_horizontal"
         android:src="@drawable/ic_lock_24dp"
         android:scaleType="center"
-        android:tint="#ffffffff"
         android:contentDescription="@string/accessibility_unlock_button" />
 
 </com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index 97697189..6a4ac2c 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -23,11 +23,19 @@
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     >
-    <ImageView
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:theme="@style/DualToneLightTheme"
         android:id="@+id/mobile_signal"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         />
+    <com.android.systemui.statusbar.AlphaOptimizedImageView
+        android:theme="@style/DualToneDarkTheme"
+        android:id="@+id/mobile_signal_dark"
+        android:layout_height="wrap_content"
+        android:layout_width="wrap_content"
+        android:alpha="0.0"
+        />
     <ImageView
         android:id="@+id/mobile_type"
         android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout/segmented_button.xml b/packages/SystemUI/res/layout/segmented_button.xml
index e92f310..ead735f 100644
--- a/packages/SystemUI/res/layout/segmented_button.xml
+++ b/packages/SystemUI/res/layout/segmented_button.xml
@@ -19,10 +19,10 @@
     android:layout_height="wrap_content"
     android:layout_marginStart="@dimen/segmented_button_spacing"
     android:layout_weight="1"
-    android:gravity="center_horizontal|top"
+    android:paddingStart="8dp"
+    android:gravity="start|center_vertical"
+    android:maxLines="2"
     android:textColor="@color/segmented_button_text_selector"
     android:background="@drawable/btn_borderless_rect"
-    android:textAppearance="@style/TextAppearance.QS.SegmentedButton"
-    android:minHeight="64dp"
-    android:paddingTop="11dp"
-    android:drawablePadding="6dp" />
+    android:textAppearance="@style/TextAppearance.Volume.ZenSwitchSummary"
+    android:minHeight="48dp" />
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 8fbd8f7..c9edef8 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -38,11 +38,19 @@
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         >
-        <ImageView
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:theme="@style/DualToneLightTheme"
             android:id="@+id/wifi_signal"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             />
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:theme="@style/DualToneDarkTheme"
+            android:id="@+id/wifi_signal_dark"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:alpha="0.0"
+            />
     </FrameLayout>
     <View
         android:id="@+id/wifi_signal_spacer"
@@ -56,12 +64,25 @@
         android:layout_width="wrap_content"
         >
     </LinearLayout>
-    <ImageView
-        android:id="@+id/no_sims"
+    <FrameLayout
         android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:src="@drawable/stat_sys_no_sims"
-        />
+        android:layout_width="wrap_content">
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:theme="@style/DualToneLightTheme"
+            android:id="@+id/no_sims"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:src="@drawable/stat_sys_no_sims"
+            />
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:theme="@style/DualToneDarkTheme"
+            android:id="@+id/no_sims_dark"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:src="@drawable/stat_sys_no_sims"
+            android:alpha="0.0"
+            />
+    </FrameLayout>
     <View
         android:id="@+id/wifi_airplane_spacer"
         android:layout_width="4dp"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index f717ac7..0e1517f 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -128,7 +128,7 @@
         android:id="@+id/clock"
         />
 
-    <Button android:id="@+id/alarm_status"
+    <com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_alignParentBottom="true"
diff --git a/packages/SystemUI/res/layout/status_bar_search_panel.xml b/packages/SystemUI/res/layout/status_bar_search_panel.xml
deleted file mode 100644
index e0520ef6..0000000
--- a/packages/SystemUI/res/layout/status_bar_search_panel.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- Extends FrameLayout -->
-<com.android.systemui.SearchPanelView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/search_panel_container"
-    android:layout_height="match_parent"
-    android:layout_width="match_parent">
-
-    <com.android.systemui.statusbar.AlphaOptimizedView
-        style="@style/SearchPanelScrim"
-        android:id="@+id/search_panel_scrim"
-        android:background="@drawable/search_panel_scrim" />
-
-    <com.android.systemui.SearchPanelCircleView
-        style="@style/SearchPanelCircle"
-        android:id="@+id/search_panel_circle">
-
-        <ImageView
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:id="@+id/search_logo" />
-    </com.android.systemui.SearchPanelCircleView>
-
-</com.android.systemui.SearchPanelView>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 3765fe8..7586227 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2014 The Android Open Source Project
+     Copyright (C) 2015 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,15 +13,50 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/volume_dialog"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_marginBottom="4dp"
     android:layout_marginLeft="@dimen/notification_side_padding"
     android:layout_marginRight="@dimen/notification_side_padding"
-    android:background="@drawable/qs_background_primary"
-    android:translationZ="@dimen/volume_panel_z"
-    android:layout_marginBottom="@dimen/volume_panel_z">
+    android:layout_marginTop="4dp"
+    android:background="@drawable/volume_dialog_background"
+    android:translationZ="4dp" >
 
-        <include layout="@layout/volume_panel" />
+    <com.android.keyguard.AlphaOptimizedImageButton
+        android:id="@+id/volume_expand_button"
+        style="@style/VolumeButtons"
+        android:layout_alignParentLeft="true"
+        android:layout_width="@dimen/volume_button_size"
+        android:layout_height="@dimen/volume_button_size"
+        android:clickable="true"
+        android:soundEffectsEnabled="false"
+        android:src="@drawable/ic_volume_collapse_animation" />
 
-</FrameLayout>
\ No newline at end of file
+    <LinearLayout
+        android:id="@+id/volume_dialog_content"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:paddingBottom="4dp"
+        android:paddingEnd="4dp"
+        android:paddingStart="4dp"
+        android:paddingTop="6dp" >
+
+        <!-- volume rows added and removed here! :-) -->
+
+        <FrameLayout
+            android:id="@+id/volume_footer"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            tools:ignore="UselessParent" >
+
+            <include layout="@layout/volume_text_footer" />
+
+            <include layout="@layout/volume_zen_footer" />
+        </FrameLayout>
+    </LinearLayout>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
new file mode 100644
index 0000000..af27cc4
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -0,0 +1,64 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false" >
+
+    <TextView
+        android:id="@+id/volume_row_header"
+        style="?android:attr/textAppearanceButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:alpha="@dimen/volume_secondary_alpha"
+        android:ellipsize="end"
+        android:maxLines="1"
+        android:paddingBottom="0dp"
+        android:paddingEnd="12dp"
+        android:paddingStart="13dp"
+        android:paddingTop="8dp" />
+
+    <com.android.keyguard.AlphaOptimizedImageButton
+        android:id="@+id/volume_row_icon"
+        style="@style/VolumeButtons"
+        android:layout_width="@dimen/volume_button_size"
+        android:layout_height="@dimen/volume_button_size"
+        android:layout_below="@id/volume_row_header"
+        android:soundEffectsEnabled="false" />
+
+    <SeekBar
+        android:id="@+id/volume_row_slider"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBottom="@+id/volume_row_icon"
+        android:layout_alignWithParentIfMissing="true"
+        android:layout_below="@id/volume_row_header"
+        android:layout_toEndOf="@id/volume_row_icon"
+        android:layout_toStartOf="@+id/volume_settings_button"
+        android:paddingEnd="4dp"
+        android:paddingStart="4dp"
+        android:progressTint="@android:color/white"
+        android:thumbTint="@android:color/white" />
+
+    <com.android.keyguard.AlphaOptimizedImageButton
+        android:id="@+id/volume_settings_button"
+        style="@style/VolumeButtons"
+        android:layout_width="@dimen/volume_button_size"
+        android:layout_height="@dimen/volume_button_size"
+        android:layout_alignParentEnd="true"
+        android:layout_below="@id/volume_row_header" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_panel_dialog.xml b/packages/SystemUI/res/layout/volume_panel_dialog.xml
new file mode 100644
index 0000000..700102f
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_panel_dialog.xml
@@ -0,0 +1,27 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginBottom="@dimen/volume_panel_z"
+    android:layout_marginLeft="@dimen/notification_side_padding"
+    android:layout_marginRight="@dimen/notification_side_padding"
+    android:background="@drawable/qs_background_primary"
+    android:translationZ="@dimen/volume_panel_z" >
+
+    <include layout="@layout/volume_panel" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_text_footer.xml b/packages/SystemUI/res/layout/volume_text_footer.xml
new file mode 100644
index 0000000..7436488
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_text_footer.xml
@@ -0,0 +1,54 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/volume_text_footer"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:visibility="gone"
+    tools:ignore="UselessParent" >
+
+    <TextView
+        android:id="@+id/volume_footline_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignBaseline="@+id/volume_footline_action_button"
+        android:alpha="@dimen/volume_secondary_alpha"
+        android:fontFamily="sans-serif"
+        android:paddingEnd="8dp"
+        android:paddingStart="13dp"
+        android:textColor="?android:attr/textColorPrimary" />
+
+    <Button
+        android:id="@+id/volume_footline_action_button"
+        style="@android:style/Widget.Material.Button.Borderless"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/volume_button_size"
+        android:layout_toEndOf="@id/volume_footline_text"
+        android:layout_toStartOf="@+id/volume_settings_button"
+        android:alpha="@dimen/volume_secondary_alpha"
+        android:paddingEnd="0dp"
+        android:paddingStart="0dp" />
+
+    <com.android.keyguard.AlphaOptimizedImageButton
+        android:id="@+id/volume_settings_button"
+        style="@style/VolumeButtons"
+        android:layout_width="@dimen/volume_button_size"
+        android:layout_height="@dimen/volume_button_size"
+        android:layout_alignParentEnd="true"
+        android:src="@drawable/ic_volume_settings" />
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
new file mode 100644
index 0000000..c491e9c
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -0,0 +1,108 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<com.android.systemui.volume.ZenFooter xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/volume_zen_footer"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" > <!-- extends LinearLayout -->
+
+    <LinearLayout
+        android:id="@+id/volume_zen_switch_bar"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/volume_button_size"
+        android:clickable="true"
+        android:orientation="horizontal" >
+
+        <ImageView
+            android:id="@+id/volume_zen_switch_bar_icon"
+            android:layout_width="@dimen/volume_button_size"
+            android:layout_height="@dimen/volume_button_size"
+            android:scaleType="center"
+            android:src="@drawable/ic_dnd" />
+
+        <TextView
+            android:layout_width="0dp"
+            android:layout_height="fill_parent"
+            android:layout_weight="1"
+            android:gravity="center_vertical"
+            android:textDirection="locale"
+            android:padding="3dp"
+            android:text="@string/volume_zen_switch_text"
+            android:textAppearance="@style/TextAppearance.Volume.ZenSwitch" />
+
+        <Switch
+            android:id="@+id/volume_zen_switch"
+            android:layout_width="wrap_content"
+            android:layout_height="fill_parent"
+            android:layout_marginEnd="11dp" />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:id="@+id/volume_zen_panel_summary"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/volume_button_size"
+        android:layout_marginStart="@dimen/volume_button_size"
+        android:paddingEnd="3dp"
+        android:paddingStart="3dp" >
+
+        <TextView
+            android:id="@+id/volume_zen_panel_summary_line_1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Volume.ZenSwitchSummary" />
+
+        <TextView
+            android:id="@+id/volume_zen_panel_summary_line_2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/volume_zen_panel_summary_line_1"
+            android:textAppearance="@style/TextAppearance.Volume.ZenSwitchDetail" />
+    </RelativeLayout>
+
+    <include layout="@layout/zen_mode_panel" />
+
+    <LinearLayout
+        android:id="@+id/volume_zen_mode_panel_buttons"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="end" >
+
+        <TextView
+            android:id="@+id/volume_zen_mode_panel_more"
+            style="@style/QSBorderlessButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginEnd="8dp"
+            android:clickable="true"
+            android:focusable="true"
+            android:minWidth="132dp"
+            android:text="@string/quick_settings_more_settings"
+            android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+        <TextView
+            android:id="@+id/volume_zen_mode_panel_done"
+            style="@style/QSBorderlessButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:clickable="true"
+            android:focusable="true"
+            android:minWidth="66dp"
+            android:text="@string/quick_settings_done"
+            android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+    </LinearLayout>
+
+</com.android.systemui.volume.ZenFooter>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml
index 0b91913..a169d1a 100644
--- a/packages/SystemUI/res/layout/zen_mode_condition.xml
+++ b/packages/SystemUI/res/layout/zen_mode_condition.xml
@@ -18,8 +18,8 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/qs_detail_item_height"
     android:layout_marginBottom="@dimen/zen_mode_condition_detail_item_spacing"
-    android:layout_marginStart="@dimen/zen_mode_condition_detail_button_padding"
-    android:layout_marginEnd="@dimen/zen_mode_condition_detail_button_padding" >
+    android:layout_marginStart="1dp"
+    android:layout_marginEnd="0dp" >
 
     <RadioButton
         android:id="@android:id/checkbox"
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 33c1899..3d73ff7 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -19,6 +19,7 @@
     android:id="@+id/zen_mode_panel"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:layout_marginStart="35dp"
     android:clipChildren="false"
     android:orientation="vertical" >
 
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index a74e120..5a85177 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Skakel batterybespaarder aan"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Outodraai skerm"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMP"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"OUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus aangeskakel."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Moenie steur nie aan, net prioriteit."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Moenie steur nie aan, geen onderbrekings nie."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\'Moenie steur nie\' is aan, net wekkers."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Moenie steur nie af."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Moenie steur nie is afgeskakel."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Moenie steur nie is aangeskakel."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Nageregkas"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Sluimer"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Moenie steur nie"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Net prioriteit"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Net wekkers"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Geen onderbrekings nie"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> toestelle)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Geen onderbrekings nie. Nie eens wekkers nie."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Geen onderbrekings nie"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Net prioriteitonderbrekings"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Net wekkers"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Jou volgende wekker is om <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Jou volgende wekker is <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Jy sal nie jou wekker om <xliff:g id="ALARM_TIME">%s</xliff:g> hoor nie"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Sleep op om te ontsluit"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Sleep regs vir foon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Sleep links vir kamera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Geen"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioriteit"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Net wekkers"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Alles"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Geen\nonderbrekings nie"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Net\nprioriteit"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Net\nwekkers"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Wissel gebruiker"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Wissel gebruiker, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Weier"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is die volumedialoog"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Raak om die oorspronklike terug te stel."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 0c9aa53..cc78112 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ባትሪ ቆጣቢን አብራ"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ቅንብሮች"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"የአውሮፕላን ሁነታ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ማያ በራስ ሰር አሽከርክር"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ድምጽ አጥፋ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ራስ ሰር"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"የአውሮፕላን ሁነታ በርቷል።"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"አትረብሽ በርቷል፣ ቅድሚያ የሚሰጠው ብቻ።"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"አትረብሽ በርቷል፣ ምንም ማቋረጦች የሉም።"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"አትረብሽ በርቷል፣ ማንቂያዎች ብቻ።"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"አትረብሽ ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"አትረብሽ ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"አትረብሽ በርቷል።"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"የማወራረጃ ምግቦች መያዣ"</string>
     <string name="start_dreams" msgid="7219575858348719790">"የቀን ህልም"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ኤተርኔት"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"የአውሮፕላን ሁነታ"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"አትረብሽ"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ቅድሚያ የሚሰጠው ብቻ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"ማንቂያዎች ብቻ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ምንም ማቋረጦች የሉም"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ብሉቱዝ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ብሉቱዝ (<xliff:g id="NUMBER">%d</xliff:g> መሣሪያዎች)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ምንም ማቋረጦች የሉም። ማንቂያዎችም እንኳ።"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"ምንም ማቋረጦች የሉም"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ቅድሚያ የሚሰጣቸው ማቋረጦች ብቻ"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"ማንቂያዎች ብቻ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"ቀጣዩ ማንቂያ ደውልዎ በ<xliff:g id="ALARM_TIME">%s</xliff:g> ነው"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ቀጣዩ ማንቂያ ደውልዎ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> ነው"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"በ<xliff:g id="ALARM_TIME">%s</xliff:g> ያለውን ማንቂያ ደውልዎን አይሰሙትም"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"ለማስከፈት ወደ ላይ ያንሸራትቱ"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ለስልክ ወደቀኝ ያንሸራትቱ"</string>
     <string name="camera_hint" msgid="5241441720959174226">"ለካሜራ ወደግራ ያንሸራትቱ"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ምንም"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ቅድሚያ"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"ምንም ማቋረጦች የሉም"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"ቅድሚያ የሚሰጠው ብቻ"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"ማንቂያዎች ብቻ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"ሁሉም"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"ምንም\nመቆራረጦች የሉም"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ቅድሚያ ተሰጪ\nብቻ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ማንቂያዎች\nብቻ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ተጠቃሚ ቀይር"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ተጠቃሚ ይለውጡ፣ የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ከልክል"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> የድምጽ መጠን መገናኛው ነው"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"የመጀመሪያውን ወደነበረበት ለመመለስ ይንኩ።"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"መቆራረጦችን አግድ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index de7250d..0b8b0bf 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -48,7 +48,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"تشغيل توفير شحن البطارية"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"الإعدادات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"وضع الطائرة"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"التدوير التلقائي للشاشة"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"كتم"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"تلقائي"</string>
@@ -184,6 +183,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"تم تشغيل وضع الطائرة."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"تم تشغيل الرجاء عدم الإزعاج، الأولوية فقط."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"تم تشغيل \"الرجاء عدم الإزعاج\"، ممنوع الإزعاج."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"تم تشغيل الرجاء عدم الإزعاج، التنبيهات فقط."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"تم تعطيل \"الرجاء عدم الإزعاج\"."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"تم تعطيل \"الرجاء عدم الإزعاج\"."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"تم تشغيل \"الرجاء عدم الإزعاج\"."</string>
@@ -234,9 +234,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"حالة الحلويات"</string>
     <string name="start_dreams" msgid="7219575858348719790">"حلم اليقظة"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"وضع الطائرة"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"الرجاء عدم الإزعاج"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"الأولوية فقط"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"التنبيهات فقط"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"عدم الإزعاج"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث (<xliff:g id="NUMBER">%d</xliff:g> من الأجهزة)"</string>
@@ -307,6 +307,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"عدم المقاطعة، ولا بالتنبيهات كذلك."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"بدون مقاطعات"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"المقاطعات ذات الأولوية فقط"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"التنبيهات فقط"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"التنبيه المقبل في <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"التنبيه المقبل في <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"لن تسمع المنبهات في <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -316,9 +317,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"مرر سريعًا لأعلى لإلغاء القفل"</string>
     <string name="phone_hint" msgid="3101468054914424646">"مرر سريعًا إلى اليسار لفتح الهاتف"</string>
     <string name="camera_hint" msgid="5241441720959174226">"مرر سريعًا إلى اليمين لفتح الكاميرا"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"بدون"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"الأولوية"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"عدم الإزعاج"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"الأولوية فقط"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"التنبيهات فقط"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"الكل"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"عدم\nالإزعاج"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"الأولوية \nفقط"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"التنبيهات\nفقط"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تبديل المستخدم"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تبديل المستخدم، المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -386,4 +391,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"رفض"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> هو مربع حوار مستوى الصوت"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"المس لاستعادة الإعداد الأصلي."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"حظر المقاطعات"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 1f69b11..845c7c2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Включване на режима за запазване на батерията"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Самолетен режим"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Авт. завъртане на екрана"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"БЕЗ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТ."</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Самолетният режим се включи."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Настройката „Не безпокойте“ е включена – само с приоритет."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Настройката „Не безпокойте“ е включена – без прекъсвания."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Настройката „Не безпокойте“ е включена в режим само с будилници."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Настройката „Не безпокойте“ е изключена."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Настройката „Не безпокойте“ е изключена."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Настройката „Не безпокойте“ е включена."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Витрина с десерти"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Мечта"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Самолетен режим"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не безпокойте"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Само с приоритет"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Само будилници"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без прекъсвания"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> устройства)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Без прекъсвания. Дори без будилници."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Без прекъсвания"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Само приоритетни прекъсвания"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Само будилници"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Следващият ви будилник е в <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Следващият ви будилник е в/ъв <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Няма да чуете будилника си в <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Прекарайте пръст нагоре, за да отключите"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Прекарайте пръст надясно, за да използвате телефона"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Прекарайте пръст наляво, за да включите камерата"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Няма"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Приоритет"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Само будилници"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Всички"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Без\nпрекъсвания"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nс приоритет"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nбудилници"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Превключване между потребителите"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Превключване на потребителя – текущият е <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Отказване"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> изпълнява ролята на диалоговия прозорец за силата на звука"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Докоснете, за да възстановите оригинала."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 26fd0f4..62cb021 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ব্যাটারি সঞ্চয়কারী চালু"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"সেটিংস"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"বিমান মোড"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"স্বতঃ-ঘূর্ণায়মান স্ক্রীণ"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"নিঃশব্দ করুন"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"স্বতঃ"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"বিমান মোড চালু হয়েছে।"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"“বিরক্ত করবেন না” চালু করবেন, শুধুমাত্র অগ্রাধিকার৷"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"“বিরক্ত করবেন না” চালু করবেন, কোন বাধা নয়"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"“বিরক্ত করবেন না” চালু করবেন, শুধুমাত্র অ্যালার্মগুলি৷"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"“বিরক্ত করবেন না” বন্ধ৷"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"বিরক্ত করবেন না বন্ধ রয়েছে৷"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"বিরক্ত করবেন না চালু রয়েছে৷"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ডেজার্ট কেস"</string>
     <string name="start_dreams" msgid="7219575858348719790">"স্ক্রিনসেভার"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ইথারনেট"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"বিমান মোড"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"বিরক্ত করবেন না"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"শুধুমাত্র অগ্রাধিকার"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"শুধুমাত্র অ্যালার্মগুলি"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"কোনো বাধা নয়"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> টি ডিভাইস)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"কোনো ব্যাঘাত ছাড়াই। এমনকি অ্যালার্মও নয়।"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"কোনো বাধা নয়"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"শুধুমাত্র প্রাধান্য বাধাগুলি"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"শুধুমাত্র অ্যালার্মগুলি"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"আপনার পরবর্তী অ্যালার্মের সময় <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"আপনার পরবর্তী অ্যালার্মের সময় <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> বাজলে আপনি অ্যালার্ম শুনতে পাবেন না"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"আনলক করতে উপরের দিকে সোয়াইপ করুন"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ফোনের জন্য ডানদিকে সোয়াইপ করুন"</string>
     <string name="camera_hint" msgid="5241441720959174226">"ক্যামেরার জন্য ডানদিকে সোয়াইপ করুন"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"কোনো কিছুই নয়"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"অগ্রাধিকার"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"কোনো বাধা নেই"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"শুধুমাত্র অগ্রাধিকার"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"শুধুমাত্র অ্যালার্মগুলি"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"সমস্ত"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"কোনো\nবাঁধাদান নেই"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"শুধুমাত্র\nঅগ্রাধিকার"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"শুধুমাত্র\nঅ্যালার্মগুলি"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ব্যবহারকারী পাল্টে দিন"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ব্যবহারকারী পাল্টান, বর্তমান ব্যবহারকারী <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"প্রত্যাখ্যান করুন"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> হল ভলিউম ডায়লগ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"আসলটি পুনঃস্থাপন করতে স্পর্শ করুন৷"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"বাধাগুলিকে অবরুদ্ধ করুন"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 2454adb..3a35589 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activa l\'estalvi de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuració"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode d\'avió"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Gira pantalla automàticament"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"Silen."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO."</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"S\'ha activat el Mode d\'avió."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"El mode No molesteu està activat (només amb prioritat)."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"El mode No molesteu està activat (cap interrupció)."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"El mode No molesteu està activat (només alarmes)."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"El mode No molesteu està desactivat."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"S\'ha desactivat el mode No molesteu."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"S\'ha activat el mode No molesteu."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Capsa de postres"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Estalvi de pantalla"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode d\'avió"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molesteu"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Només amb prioritat"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Només alarmes"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Cap interrupció"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositius)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Sense interrupcions (ni tan sols alarmes)"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Cap interrupció"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Només interrupcions amb prioritat"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Només alarmes"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"La propera alarma és a les <xliff:g id="ALARM_TIME">%s</xliff:g>."</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Propera alarma: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"No sentiràs l\'alarma a les <xliff:g id="ALARM_TIME">%s</xliff:g>."</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Fes lliscar el dit cap amunt per desbloquejar el teclat."</string>
     <string name="phone_hint" msgid="3101468054914424646">"Fes lliscar el dit cap a la dreta per obrir el telèfon."</string>
     <string name="camera_hint" msgid="5241441720959174226">"Fes lliscar el dit cap a l\'esquerra per obrir la càmera."</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Cap"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritat"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Només alarmes"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Totes"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Sense\ninterrupcions"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia l\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denega"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> és el diàleg de volum"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca per restaurar l\'original."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index a3ba579..fb2789a 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Zapnout úsporu baterie"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavení"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim Letadlo"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autom. otočení obrazovky"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ZTLUM."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
@@ -184,6 +183,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Režim Letadlo je zapnutý."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Stav Nerušit je zapnutý – pouze prioritní vyrušení."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Stav Nerušit je zapnutý – žádná vyrušení."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Nerušit, pouze budíky"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Stav Nerušit je vypnutý."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Stav Nerušit je vypnutý"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Stav Nerušit je zapnutý."</string>
@@ -234,9 +234,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Pult se sladkostmi"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Spořič obrazovky"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim Letadlo"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nerušit"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Pouze prioritní"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Pouze budíky"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Žádná vyrušení"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> zařízení)"</string>
@@ -307,6 +307,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Žádná vyrušení, dokonce ani budíky."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Žádná vyrušení"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Pouze prioritní vyrušení"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Pouze budíky"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Další budík je nastaven na: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Další budík: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Neuslyšíte budík v <xliff:g id="ALARM_TIME">%s</xliff:g>."</string>
@@ -316,9 +317,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zařízení odemknete přejetím prstem nahoru"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telefon otevřete přejetím prstem vpravo."</string>
     <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otevřete přejetím prstem vlevo."</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Žádné"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritní"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Pouze budíky"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Vše"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Nerušit\n"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Pouze\nprioritní"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Pouze\nbudíky"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Přepnout uživatele"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Přepnout uživatele, aktuální uživatel: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -386,4 +393,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmítnout"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dialog hlasitosti"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Klepnutím obnovíte originál."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2d4fa0f..0abbbb1 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktivér batterisparefunktion"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Indstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flytilstand"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatisk skærmrotation"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"LYDLØS"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flytilstand er slået til."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Vil ikke forstyrres\" er slået til, kun prioritet."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Vil ikke forstyrres\" er slået til, ingen afbrydelser."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Vil ikke forstyrres\" er slået til, kun alarmer."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Vil ikke forstyrres\" er slået fra."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Vil ikke forstyrres\" er slået fra."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Vil ikke forstyrres\" er slået til."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertcase"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flytilstand"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Vil ikke forstyrres"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun Alarmer"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ingen afbrydelser"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheder)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Ingen afbrydelser. Ikke engang alarmer."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Ingen afbrydelser"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Kun prioriterede afbrydelser"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Kun Alarmer"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Dit næste alarm er indstillet til kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Din næste alarm er indstillet til <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Du vil ikke kunne høre din alarm kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Stryg for at låse op"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Stryg til højre for at bruge telefonen"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Stryg til venstre for at åbne kameraet"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ingen"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritet"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Kun Alarmer"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Ingen\nafbrydelser"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Oplader (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skift bruger"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skift bruger. Nuværende bruger er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afvis"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er dialogboksen for lydstyrke"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tryk for at gendanne originalen."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index d97a063..db43dfc 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Energiesparmodus aktivieren"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Einstellungen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flugmodus"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Bildschirm automatisch drehen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"STUMM"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Der Flugmodus ist aktiviert."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Nicht stören\" an, nur wichtige Unterbrechungen"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Nicht stören\" an, keine Unterbrechungen"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Nicht stören\" an, nur Wecker"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Nicht stören\" aus"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Nicht stören\" deaktiviert"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Nicht stören\" aktiviert"</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertbehälter"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugmodus"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nicht stören"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Nur wichtige Unterbrechungen"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Nur Wecker"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Keine Unterbrechungen"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Geräte)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Keine Unterbrechungen. Auch keine Weckrufe."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Keine Unterbrechungen"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Nur wichtige Unterbrechungen"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Nur Wecker"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Nächster Weckruf: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Nächster Weckruf: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Lautloser Weckruf um <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zum Entsperren nach oben wischen"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Zum Öffnen des Telefons nach rechts wischen"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Zum Öffnen der Kamera nach links wischen"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Keine"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Wichtig"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Nur Wecker"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Keine\nUnterbrechungen"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Nur\nwichtige"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Nur\nWecker"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Nutzer wechseln"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Nutzer wechseln. Aktueller Nutzer: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -372,8 +379,8 @@
     <string name="notification_collapse_button_text" msgid="6883253262134328057">"Alle ausblenden"</string>
     <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Bildschirm ist fixiert"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Hiermit wird sie angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Zurück\" und \"Übersicht\" gleichzeitig, um die Fixierung aufzuheben."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Hiermit wird sie angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Übersicht\", um die Fixierung aufzuheben."</string>
+    <string name="screen_pinning_description" msgid="1346522416878235405">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Zurück\" und \"Übersicht\" gleichzeitig, um die Fixierung aufzuheben."</string>
+    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Übersicht\", wenn Sie die Fixierung aufheben möchten."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nein danke"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ablehnen"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> regelt die Lautstärke."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Zum Wiederherstellen des Originals hier tippen"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 5ccd669..9450cb8 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Ενεργοποίηση της εξοικονόμησης μπαταρίας"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ρυθμίσεις"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Λειτουργία πτήσης"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Αυτόματη περιστροφή οθόνης"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ΣΙΓΑΣΗ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ΑΥΤΟΜ."</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ενεργή λειτουργία πτήσης."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε, μόνο προτεραιότητας."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε, χωρίς διακοπές."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Μην ενοχλείτε, μόνο ειδοποιήσεις."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Η λειτουργία \"Μην ενοχλείτε\" απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Η λειτουργία \"Μην ενοχλείτε\" απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Η λειτουργία \"Μην ενοχλείτε\" ενεργοποιήθηκε."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Επιδόρπιο"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Λειτουργία πτήσης"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Μην ενοχλείτε"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Μόνο προτεραιότητας"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Μόνο ειδοποιήσεις"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Χωρίς διακοπές"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> συσκευές)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Χωρίς διακοπές. Ούτε ειδοποιήσεις,"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Χωρίς διακοπές"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Μόνο διακοπές προτεραιότητας"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Μόνο ειδοποιήσεις"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Το επόμενο ξυπνητήρι είναι στις <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Το επόμενο ξυπνητήρι είναι στις <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Δεν θα ακούτε το ξυπνητήρι σας στις <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Σύρετε για να ξεκλειδώσετε"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Σύρετε προς τα δεξιά για το τηλέφωνο"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Σύρετε αριστερά για τη φωτογραφική μηχανή"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Κανένα"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Προτεραιότητα"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Μόνο ειδοποιήσεις"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Όλα"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Χωρίς\nδιακοπές"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Μόνο\nπροτεραιότητας"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Μόνο\nειδοποιήσεις"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Εναλλαγή χρήστη"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Εναλλαγή χρήστη, τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Απόρριψη"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> αποτελεί το παράθυρο διαλόγου ελέγχου έντασης"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Αγγίξτε για επαναφορά αρχικού."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index dffe8ce..2f5c937 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Aeroplane mode turned on."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'Do not disturb\' on, priority only."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'Do not disturb\' on, no interruptions."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Do not disturb on, alarms only."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'Do not disturb\' off."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'Do not disturb\' turned off."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'Do not disturb\' turned on."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"No interruptions"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"No interruptions. Not even alarms."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"No interruptions"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Priority interruptions only"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alarms only"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Your next alarm is at <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Your next alarm is <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"You won\'t hear your alarm at <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Swipe right for phone"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"None"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Priority"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"No interruptions"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Priority only"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alarms only"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"No\ninterruptions"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Deny"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is the volume dialogue"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Touch to restore the original."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Block interruptions"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index dffe8ce..2f5c937 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Aeroplane mode turned on."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'Do not disturb\' on, priority only."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'Do not disturb\' on, no interruptions."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Do not disturb on, alarms only."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'Do not disturb\' off."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'Do not disturb\' turned off."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'Do not disturb\' turned on."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"No interruptions"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"No interruptions. Not even alarms."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"No interruptions"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Priority interruptions only"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alarms only"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Your next alarm is at <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Your next alarm is <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"You won\'t hear your alarm at <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Swipe right for phone"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"None"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Priority"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"No interruptions"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Priority only"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alarms only"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"No\ninterruptions"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Deny"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is the volume dialogue"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Touch to restore the original."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Block interruptions"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index dffe8ce..2f5c937 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Turn on battery saver"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Settings"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Aeroplane mode"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Auto-rotate screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Aeroplane mode turned on."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'Do not disturb\' on, priority only."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'Do not disturb\' on, no interruptions."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Do not disturb on, alarms only."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'Do not disturb\' off."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'Do not disturb\' turned off."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'Do not disturb\' turned on."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Aeroplane mode"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Do not disturb"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priority only"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarms only"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"No interruptions"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Devices)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"No interruptions. Not even alarms."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"No interruptions"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Priority interruptions only"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alarms only"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Your next alarm is at <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Your next alarm is <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"You won\'t hear your alarm at <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swipe up to unlock"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Swipe right for phone"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Swipe left for camera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"None"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Priority"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"No interruptions"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Priority only"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alarms only"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"All"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"No\ninterruptions"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Deny"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is the volume dialogue"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Touch to restore the original."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Block interruptions"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index af28b22..4c8ef14 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activar ahorro de batería"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar la pantalla automáticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SILENC"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modo de avión activado"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"No molestar activado (solo prioridad)"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"No molestar activado (sin interrupciones)"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"No molestar activado (solo alarmas)"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"No molestar desactivado"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"No molestar desactivado"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"No molestar activado"</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Caja para postres"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Activar protector"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molestar"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo prioridad"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Solo alarmas"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sin interrupciones"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Sin interrupciones (ni siquiera alarmas)"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Sin interrupciones"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Solo interrupciones de prioridad"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Solo alarmas"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Próxima alarma a la(s) <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Próxima alarma: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"No oirás la alarma a la(s) <xliff:g id="ALARM_TIME">%s</xliff:g>."</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar el dedo hacia arriba para desbloquear"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Desliza hacia la derecha para abrir el teléfono."</string>
     <string name="camera_hint" msgid="5241441720959174226">"Desliza hacia la izquierda para acceder a la cámara."</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ninguno"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioridad"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Solo alarmas"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Todo"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Sin\ninterrupciones"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\nprioridad"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rechazar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> es el cuadro de diálogo de volumen."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar el original."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 989691a..a13c5ef 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activar ahorro de energía"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ajustes"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar pantalla automáticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SILENC"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modo avión activado."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"No molestar activado (solo prioritarias)."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"No molestar activado (sin interrupciones)."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"No molestar activado, solo alarmas."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"No molestar desactivado."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"No molestar desactivado."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"No molestar activado."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Caja para postres"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Salvapantallas"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"No molestar"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo prioritarias"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Solo alarmas"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sin interrupciones"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Sin interrupciones, ni siquiera alarmas."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Sin interrupciones"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Solo interrupciones de prioridad"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Solo alarmas"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Siguiente alarma: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Siguiente alarma: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"No oirás tu alarma a las <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Desliza el dedo hacia arriba para desbloquear"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Desliza el dedo hacia la derecha para acceder al teléfono"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Desliza el dedo hacia la izquierda para acceder a la cámara"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nada"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioridad"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Solo alarmas"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Todo"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Sin\ninterrupciones"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\ncon prioridad"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar de usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rechazar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> es el cuadro de diálogo de volumen"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar la versión original."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 110ee53..1611638 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Akusäästja sisselülitamine"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Seaded"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lennurežiim"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Pööra ekraani automaatselt"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"SUMMUTA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lennukirežiim on sisse lülitatud."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Funktsioon Mitte segada on sisse lülitatud (ainult prioriteetsed)."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Funktsioon Mitte segada on sisse lülitatud (mitte ühtegi katkestust)."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Funktsioon Mitte segada on sisse lülitatud (ainult alarmid)."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Funktsioon Mitte segada on välja lülitatud."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Funktsioon Mitte segada on välja lülitatud."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Funktsioon Mitte segada on sisse lülitatud."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Maiustusekorv"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Unistus"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lennurežiim"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Mitte segada"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Ainult prioriteetsed"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Ainult alarmid"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Mitte ühtegi katkestust"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> seadet)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Katkestusi pole. Pole isegi hoiatusi."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Mitte ühtegi katkestust"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Ainult prioriteetsed katkestused"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Ainult alarmid"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Teie järgmine äratus on <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Teie järgmine äratus on <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Te ei kuule äratust <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Lukustuse tühistamiseks pühkige üles"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telefoni kasutamiseks pühkige paremale"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Kaamera kasutamiseks pühkige vasakule"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Puudub"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioriteet"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Ainult alarmid"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Kõik"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Katkestusi\npole"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Ainult\nprioriteetsed"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ainult\nalarmid"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kasutaja vahetamine"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kasutaja vahetamine, praegune kasutaja: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Keela"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on helitugevuse dialoog"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Originaali taastamiseks puudutage."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 220a5f0..9318c11 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktibatu bateria aurrezteko aukera"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ezarpenak"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Hegaldi modua"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Biratu pantaila automatikoki"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DESAKTIBATU AUDIOA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Hegaldi modua aktibatu egin da."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Ez molestatu\" aukera aktibatuta dago, lehentasunezkoak soilik."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Ez molestatu\" aukera aktibatuta dago, etenaldirik gabe."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Ez molestatu\" aukera aktibatuta dago, alarmak soilik."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Ez molestatu\" aukera desaktibatuta dago."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Ez molestatu\" aukera desaktibatuta dago."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Ez molestatu\" aukera aktibatuta dago."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Postreen kutxa"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Pantaila-babeslea"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hegaldi modua"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ez molestatu"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Lehentasunezkoak soilik"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarmak soilik"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Etenaldirik gabe"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetootha (<xliff:g id="NUMBER">%d</xliff:g> gailu)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Etenaldirik ez, ezta alarmaren bat bada ere."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Etenaldirik gabe"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Lehentasun-etenaldiak soilik"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alarmak soilik"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Hurrengo alarma: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Hurrengo alarma: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Ez duzu entzungo alarma ordu honetan: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Desblokeatzeko, pasatu hatza gorantz"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telefonoa irekitzeko, pasatu hatza eskuinera."</string>
     <string name="camera_hint" msgid="5241441720959174226">"Kamera irekitzeko, pasatu hatza ezkerrera."</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Bat ere ez"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Lehentas."</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Etenaldirik gabe"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Lehentasunezkoak"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alarmak soilik"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Guztiak"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Etenaldirik\ngabe"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Lehentasunezkoak\nsoilik"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmak\nsoilik"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Aldatu erabiltzailea"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Aldatu erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ukatu"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> da bolumenaren leihoa"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Ukitu jatorrizkora leheneratzeko"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Blokeatu etenaldiak"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index b6a6ecb..915e470 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ذخیره‌کننده باتری را روشن کنید"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"تنظیمات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"حالت هواپیما"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"چرخش خودکار صفحه"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"بی‌صدا"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"خودکار"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"حالت هواپیما روشن شد."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"«مزاحم نشوید» روشن است، فقط اولویت‌دار."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"«مزاحم نشوید» روشن است، وقفه ایجاد نشود."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"حالت «مزاحم نشوید» روشن است، فقط هشدارها."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"«مزاحم نشوید» خاموش است."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"«مزاحم نشوید» خاموش شد."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"«مزاحم نشوید» روشن شد."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ویترین دسر"</string>
     <string name="start_dreams" msgid="7219575858348719790">"رویاپردازی"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"اترنت"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"حالت هواپیما"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"مزاحم نشوید"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"فقط اولویت‌دار"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"فقط هشدارها"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"وقفه ایجاد نشود"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث ( <xliff:g id="NUMBER">%d</xliff:g> دستگاه)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"بدون قطعی. حتی هشدارها قطع نمی‌شوند."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"بدون وقفه"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"فقط وقفه‌های اولویت‌دار"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"فقط هشدارها"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"هشدار بعدی شما در ساعت <xliff:g id="ALARM_TIME">%s</xliff:g> است"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"هشدار بعدی شما <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> است"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"هشدارتان را در ساعت <xliff:g id="ALARM_TIME">%s</xliff:g> نخواهید شنید"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"برای باز کردن قفل سریع به بالا بکشید"</string>
     <string name="phone_hint" msgid="3101468054914424646">"برای تلفن انگشت را تند به سمت چپ بکشید"</string>
     <string name="camera_hint" msgid="5241441720959174226">"برای دوربین انگشت را تند به سمت راست بکشید"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"هیچ‌کدام"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"اولویت"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"بدون وقفه"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"فقط اولویت‌دار"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"فقط هشدارها"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"همه"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"بدون\nوقفه"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"فقط\nاولویت‌دار"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"فقط\nهشدارها"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تغییر کاربر"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تعویض کاربر، کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"رد کردن"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> کنترل‌کننده صدا است"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"برای بازیابی کنترل‌کننده اصلی، لمس کنید."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"مسدود کردن وقفه‌ها"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4edd4c2..680356d 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Ota virransäästö käyttöön"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Asetukset"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lentokonetila"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Kierrä näyttöä automaattisesti"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ÄÄNET."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lentokonetila otettiin käyttöön."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Älä häiritse -tila on päällä, vain tärkeät."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Älä häiritse -tila on päällä, ei keskeytyksiä."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Älä häiritse -tila on päällä, vain herätykset toistetaan."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Älä häiritse -tila on pois päältä."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Älä häiritse -tila on pois päältä."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Älä häiritse -tila on päällä."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Jälkiruokavitriini"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Unelmat"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lentokonetila"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Älä häiritse"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Vain tärkeät"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Vain herätykset"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ei häiriöitä"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> laitetta)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Ei keskeytyksiä, ei edes herätyksiä."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Ei häiriöitä"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Vain tärkeät häiriöt"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Vain herätykset"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Seuraava hälytysaika on <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Seuraava hälytysaika on <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Et kuule hälytystä klo <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Avaa lukitus pyyhkäisemällä ylös"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Avaa puhelin pyyhkäisemällä oikealle"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Avaa kamera pyyhkäisemällä oikealle"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ei mitään"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Tärkeät"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Vain herätykset"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Kaikki"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Ei\nkeskeytyksiä"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vain\ntärkeät"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vain\nherätykset"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Vaihda käyttäjää"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Vaihda käyttäjä (nyt <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Estä"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> on äänenvoimakkuusvalinta."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Palauta alkuperäinen koskettamalla."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a369dfd..89eed3e3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activer l\'économiseur d\'énergie"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotation auto de l\'écran"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUET"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOMATIQUE"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Le mode Avion est activé."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Mode « Ne pas déranger » activé, interruptions prioritaires uniquement."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Mode « Ne pas déranger » activé, sans interruption."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Mode « Ne pas déranger » activé, alarmes uniquement."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Mode « Ne pas déranger » désactivé."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Le mode « Ne pas déranger » a bien été désactivé."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Le mode « Ne pas déranger » a bien été activé."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Vitrine des desserts"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Écran de veille"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode Avion"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne pas déranger"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priorités seulement"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarmes uniquement"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Aucune interruption"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Aucune interruption. Même pas pour les alarmes."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Aucune interruption"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Interruptions prioritaires seulement"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alarmes uniquement"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Prochaine alarme : <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Prochaine alarme : <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Vous n\'entendrez pas votre alarme à <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Glissez vers le haut pour déverrouiller"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Balayez l\'écran vers la droite pour accéder au téléphone"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Balayez l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Aucun"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Priorité"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alarmes uniquement"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tous"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Aucune\ninterruption"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorités\nuniquement"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuser"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Touchez pour restaurer l\'original."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 18dac4c..ef67f67 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activer l\'économiseur de batterie"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Paramètres"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode Avion"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotation automatique de l\'écran"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUET"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Le mode Avion est activé."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Mode \"Ne pas déranger\" activé, interruptions prioritaires uniquement"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Mode \"Ne pas déranger\" activé, sans interruption"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Mode \"Ne pas déranger\" activé, alarmes uniquement"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Mode \"Ne pas déranger\" désactivé"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Le mode \"Ne pas déranger\" a bien été désactivé."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Le mode \"Ne pas déranger\" a bien été activé."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Vitrine des desserts"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Écran de veille interactif"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode avion"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne pas déranger"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Prioritaires uniquement"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alarmes uniquement"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Aucune interruption"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> appareils)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Aucune sonnerie, pas même pour les alarmes"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Aucune sonnerie"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Sonneries prioritaires uniquement"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alarmes uniquement"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Prochaine alarme : <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Prochaine alarme : <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Vous n\'entendrez pas votre alarme à <xliff:g id="ALARM_TIME">%s</xliff:g>."</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Faire glisser pour déverrouiller"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Balayer l\'écran vers la droite pour accéder au téléphone"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Balayer l\'écran vers la gauche pour accéder à l\'appareil photo"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Aucune"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritaire"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alarmes uniquement"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Toujours"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Aucune\ninterruption"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuser"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> correspond à la boîte de dialogue du volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Appuyez pour restaurer l\'interface d\'origine."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 75c0cb9..d379247 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activar o aforro de batería"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configuración"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avión"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Xirar pantalla automaticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"APAGAR"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Activouse o modo avión."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Non molestar activado, só prioridade."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Non molestar activado, sen interrupcións."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Non molestar activado, só alarmas."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"A opción Non molestar está desactivada."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Desactivouse a opción Non molestar."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Activouse a opción Non molestar."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Caixa de sobremesa"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Protector pantalla"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avión"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Non molestar"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Só prioridade"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Só alarmas"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sen interrupcións"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Non hai interrupcións nin alarmas."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Sen interrupcións"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Só interrupcións prioritarias"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Só alarmas"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"A túa próxima alarma ten lugar ás <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"A túa próxima alarma ten lugar o <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Non escoitarás a túa alarma ás <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Pasa o dedo cara arriba para desbloquear"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Pasa o dedo cara á dereita para acceder ao teléfono"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Pasa o dedo cara á esquerda para abrir a cámara"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ningún"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioridade"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Sen interrupcións"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Só prioridade"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Só alarmas"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Todas"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Ningunha\ninterrupción"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar usuario, usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +389,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denegar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é o cadro de diálogo de volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar o orixinal."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Bloquear interrupcións"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 5c45c8b..76bfb66 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"बैटरी बचतकर्ता को चालू करें"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाई-फ़ाई"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाई जहाज मोड"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्‍क्रीन अपनेआप घुमाएं"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्यूट करें"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वत:"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"हवाई जहाज़ मोड को चालू किया गया."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"परेशान ना करें चालू, केवल प्राथमिकता."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"परेशान ना करें चालू है, कोई बाधा नहीं."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"परेशान ना करें चालू, केवल अलार्म."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"परेशान ना करें बंद."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"परेशान ना करें बंद किया गया."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"परेशान ना करें चालू किया गया."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"मिठाई का डिब्बा"</string>
     <string name="start_dreams" msgid="7219575858348719790">"स्क्रीनसेवर"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ईथरनेट"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाई जहाज़ मोड"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"परेशान ना करें"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"केवल प्राथमिकता"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"केवल अलार्म"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"कोई मेसज और कॉल को नहीं रोका गया"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लूटूथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लूटूथ (<xliff:g id="NUMBER">%d</xliff:g> डिवाइस)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ऐसा सेट करें की कोई कि अलार्म भी ना हो."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"कोई अवरोध नहीं"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"केवल प्राथमिकता वाले कल और मैसेज को रोकें"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"केवल अलार्म"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"आपका अगला अलार्म <xliff:g id="ALARM_TIME">%s</xliff:g> पर है"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"आपका अगला अलार्म <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> पर है"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"आपको <xliff:g id="ALARM_TIME">%s</xliff:g> पर अपना अलार्म सुनाई नहीं देगा"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करने के लिए ऊपर स्वाइप करें"</string>
     <string name="phone_hint" msgid="3101468054914424646">"फ़ोन के लिए दाएं स्वाइप करें"</string>
     <string name="camera_hint" msgid="5241441720959174226">"कैमरे के लिए बाएं स्वाइप करें"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"कोई नहीं"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"प्राथमिकता"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"कोई बाधा नहीं"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"केवल प्राथमिकता"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"केवल अलार्म"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"सभी"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"कोई बाधा\nनहीं"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवल\nप्राथमिकता"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवल\nअलार्म"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूरा होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> बाकी)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"उपयोगकर्ता स्विच करें"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"उपयोगकर्ता स्विच करें, वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार करें"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद है"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल वॉल्यूम को फिर से लाने के लिए स्पर्श करें."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"बाधाओं को रोकें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 4210738..f4a8974 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -45,7 +45,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Uključi uštedu baterije"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Postavke"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način rada u zrakoplovu"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatski zakreni zaslon"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"Bez zv."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
@@ -181,6 +180,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Način rada u zrakoplovu uključen."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Ne ometaj\" uključeno, samo prioritetno."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Ne ometaj\" uključeno, bez prekida."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Ne ometaj\" uključeno, samo za alarme."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Ne ometaj\" isključeno."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Ne ometaj\" isključeno."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Ne ometaj\" uključeno."</string>
@@ -231,9 +231,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Izlog za slastice"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način rada u zrakoplovu"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne ometaj"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prioritetno"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Samo alarmi"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Bez prekida"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (broj uređaja: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -304,6 +304,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Bez prekida, čak ni za alarme."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Bez prekida"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Samo prioritetni prekidi"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Samo alarmi"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Vaš sljedeći alarm bit će u <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Vaš sljedeći alarm bit će u <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Nećete čuti alarm u <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -313,9 +314,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prijeđite prstom prema gore za otključavanje"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Prijeđite prstom udesno za telefon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Prijeđite prstom ulijevo za fotoaparat"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ništa"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritet"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Samo alarmi"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Sve"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Bez\nprekida"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetno"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Promjena korisnika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Promjena korisnika, trenutačni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -383,4 +390,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> predstavlja dijaloški okvir za upravljanje glasnoćom"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da biste vratili izvorno."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 2e8c4f3..4e0a7ab 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Akkumulátorkímélő mód bekapcsolása"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Beállítások"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Repülőgép üzemmód"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Képernyő automatikus forgatása"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"NÉMÍT"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Repülős üzemmód bekapcsolva."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"A „Ne zavarjanak” mód bekapcsolva. Csak prioritásos."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"A „Ne zavarjanak” mód bekapcsolva. Nincsenek értesítések."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"A „Ne zavarjanak” mód bekapcsolva. Csak riasztások."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"A „Ne zavarjanak” mód kikapcsolva."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"A „Ne zavarjanak” mód kikapcsolva."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"A „Ne zavarjanak” mód bekapcsolva."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Álmodozás"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Repülőgép üzemmód"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne zavarjanak"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Csak prioritásos"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Csak riasztások"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ne zavarjon"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> eszköz)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Semmi sem zavarja meg, még a riasztások sem."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Ne zavarjon"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Csak prioritást élvező zavaró üzenetek"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Csak riasztások"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"A következő ébresztés ideje: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"A következő ébresztés napja és ideje: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Nem fogja hallani az ébresztést ekkor: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Húzza felfelé az ujját a feloldáshoz"</string>
     <string name="phone_hint" msgid="3101468054914424646">"A telefon eléréséhez csúsztassa ujját jobbra"</string>
     <string name="camera_hint" msgid="5241441720959174226">"A fényképezőgép eléréséhez csúsztassa ujját balra"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nincs"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritást élvező"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Csak riasztások"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Összes"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Nincs\nmegszakítás"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Csak\nprioritás"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Csak\nriasztások"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Felhasználóváltás"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Felhasználóváltás (a jelenlegi felhasználó: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Elutasítás"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás kezeli a hangerőt"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Érintse meg az eredeti érték visszaállításához."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 91d36da..5d24727 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Միացնել մարտկոցի տնտեսումը"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Կարգավորումներ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Ինքնաթիռային ռեժիմ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ինքնապտտվող էկրան"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"Համրեցնել"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"Ինքնաշխատ"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ինքնաթիռային ռեժիմը միացավ:"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Չխանգարելու ընտրանքը միացված է: Ընդհատել միայն կարևոր ծանուցումների դեպքում:"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Չխանգարելու ընտրանքը միացված է: Չընդհատել:"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Չանհանգստացնել նախընտրանքը միացրած է միայն ազդանշաններում:"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Չխանգարելու ընտրանքն անջատված է:"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Չխանգարելու ընտրանքն անջատվեց:"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Չխանգարելու ընտրանքը միացվեց:"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Ցերեկային ռեժիմ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ինքնաթիռային ռեժիմ"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Չխանգարել"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Միայն կարևոր ծանուցումների դեպքում"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Միայն ազդանշաններ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Չընդհատել"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> սարք)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Առանց ընդհատումների՝ ներառյալ զարթուցիչները:"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Առանց ընդհատումների"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Միայն կարևոր ընդհատումներ"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Միայն ազդանշաններ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Ձեր հաջորդ զարթուցիչի ժամն է՝ <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Ձեր հաջորդ զարթուցիչի օրն է՝ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Դուք չեք լսի ձեր զարթուցիչը <xliff:g id="ALARM_TIME">%s</xliff:g>-ին:"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Սահեցրեք վերև` ապակողպելու համար"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Հեռախոսի համար սահեցրեք աջ"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Խցիկի համար սահեցրեք ձախ"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"-"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Կարևորություն"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Միայն ազդանշաններ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Բոլորը"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Առանց\nմիջամտության"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nազդանշաններ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Անջատել օգտվողին"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Փոխել օգտվողին. ներկայիս օգտվողն է՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Մերժել"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ը ձայնի ուժգնության երկխոսության հավելված է"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Դիպչեք՝ սկզբնօրինակը վերականգնելու համար:"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index bacca07..f138d15 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktifkan penghemat baterai"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setelan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mode pesawat"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotasi layar otomatis"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"BUNGKAM"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Mode pesawat diaktifkan."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Status \"Jangan ganggu\" aktif, hanya untuk prioritas."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Status \"Jangan ganggu\" aktif, tanpa gangguan."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Jangan ganggu aktif, hanya alarm."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Status \"Jangan ganggu\" nonaktif."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Status \"Jangan ganggu\" dinonaktifkan."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Status \"Jangan ganggu\" diaktifkan."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Etalase Hidangan Penutup"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Lamunan"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mode pesawat"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Jangan ganggu"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Hanya untuk prioritas"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Hanya alarm"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Tanpa gangguan"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Perangkat)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Tanpa gangguan, termasuk alarm."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Tidak ada interupsi"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Hanya interupsi prioritas"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Hanya alarm"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Alarm Anda berikutnya pukul <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Alarm Anda berikutnya hari <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Anda tidak akan mendengar alarm pukul <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Gesek ke kanan untuk menelepon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Gesek ke kiri untuk kamera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Tidak ada"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritas"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Tanpa gangguan"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Hanya untuk prioritas"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Hanya alarm"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Semua"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Tidak ada\ngangguan"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Hanya\nprioritas"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Hanya\nalarm"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Beralih pengguna"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ganti pengguna, pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tolak"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> adalah dialog volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Sentuh untuk memulihkan aslinya."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Blokir gangguan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index ffd3361..25ed032 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Kveikja á rafhlöðusparnaði"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Stillingar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flugstilling"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Snúa skjá sjálfkrafa"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ÞAGGA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"SJÁLFV"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Kveikt á flugstillingu."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Kveikt á „Ónáðið ekki“, aðeins forgangur."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Kveikt á „Ónáðið ekki“, engar truflanir."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Kveikt á „Ónáðið ekki“, aðeins vekjarar."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Slökkt á „Ónáðið ekki“."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Slökkt á „Ónáðið ekki“."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Kveikt á „Ónáðið ekki“."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Eftirréttaborð"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Skjávari"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flugstilling"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ónáðið ekki"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Aðeins forgangur"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Aðeins vekjarar"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Engar truflanir"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> tæki)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Engar truflanir. Ekki einu sinni vekjarar."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Engin truflun"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Aðeins forgangstruflanir"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Aðeins vekjarar"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Næsti vekjari er kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Næsti vekjari er <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Ekki mun heyrast í vekjaranum kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Strjúktu upp til að opna"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Strjúktu til hægri fyrir síma"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Strjúktu til vinstri fyrir myndavél"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Engar"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Forgangur"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Aðeins vekjarar"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Allar"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Engar\ntruflanir"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Aðeins\nforgangur"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Aðeins\nvekjarar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skipta um notanda"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skipta um notanda; núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Hafna"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er hljóðstyrksvalmyndin"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Snertu til að færa í upprunalegt horf."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 37cf79c..674849b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Attiva risparmio energetico"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Impostazioni"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modalità aereo"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotazione automatica schermo"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modalità aereo attivata."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Non disturbare\" attivo, solo con priorità."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Non disturbare\" attivo, nessuna interruzione."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Non disturbare\" attivo, solo sveglie."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Non disturbare\" non attivo."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Non disturbare\" non attivo."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Non disturbare\" attivo."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Vetrina di dolci"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modalità aereo"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Non disturbare"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Solo con priorità"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Solo sveglie"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Nessuna interruzione"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivi)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Senza interruzioni. Neanche sveglie."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Nessuna interruzione"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Solo interruzioni con priorità"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Solo sveglie"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Il tuo prossimo allarme è alle ore <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Il tuo prossimo allarme è il giorno <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Il tuo allarme non suonerà alle <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Scorri verso l\'alto per sbloccare"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Scorri verso destra per accedere al telefono"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Scorri verso sinistra per accedere alla fotocamera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nessuna"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Priorità"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Solo sveglie"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tutte"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Nessuna\ninterruzione"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo con\npriorità"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nsveglie"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambio utente"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambia utente, utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Nega"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> rappresenta la finestra di dialogo relativa al volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tocca per ripristinare l\'originale."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index f7c66f7..4043ac0 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"הפעל חיסכון בסוללה"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"הגדרות"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"מצב טיסה"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"סיבוב אוטומטי של המסך"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"השתק"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"אוטומטי"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"מצב טיסה הופעל."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\'נא לא להפריע\' פועל. הודעות בעדיפות בלבד."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\'נא לא להפריע\' פועל. ללא הפרעות."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\'נא לא להפריע\' הופעל. התראות בלבד."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\'נא לא להפריע\' כבוי."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\'נא לא להפריע\' כבוי."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\'נא לא להפריע\' פועל."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"מזנון קינוחים"</string>
     <string name="start_dreams" msgid="7219575858348719790">"חלום בהקיץ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"מצב טיסה"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"נא לא להפריע"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"עדיפות בלבד"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"התראות בלבד"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ללא הפרעות"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"‏Bluetooth ‏(<xliff:g id="NUMBER">%d</xliff:g> מכשירים)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ללא הפרעות. גם לא התראות."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"ללא הפרעות"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"רק הפרעות בעדיפות גבוהה"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"התראות בלבד"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"ההתראה הבאה שלך היא ב-<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ההתראה הבאה שלך היא ב<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"לא תשמע את ההתראה שלך ב-<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"החלק מעלה כדי לבטל את הנעילה"</string>
     <string name="phone_hint" msgid="3101468054914424646">"כדי להפעיל את הטלפון, החלק שמאלה"</string>
     <string name="camera_hint" msgid="5241441720959174226">"החלק ימינה להפעלת המצלמה"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ללא"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"עדיפות"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"ללא הפרעות"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"עדיפות בלבד"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"התראות בלבד"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"הכל"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"ללא\nהפרעות"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"החלפת משתמש"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"החלף משתמש. המשתמש הנוכחי הוא <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +389,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"דחה"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> הוא תיבת הדו-שיח של עוצמת הקול"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"גע כדי לשחזר את עוצמת הקול המקורית."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"חסימת הפרעות"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1d8a2f7..b87f265 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"バッテリーセーバーをONにします"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"機内モード"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動回転画面"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ミュート"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"オート"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"機内モードをONにしました。"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"[通知を非表示]はONで、重要な通知のみです。"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"[通知を非表示]はONで、サイレントです。"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"[通知を非表示]はONで、アラームのみです。"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"[通知を非表示]はOFFです。"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"[通知を非表示]をOFFにしました。"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"[通知を非表示]をONにしました。"</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"デザートケース"</string>
     <string name="start_dreams" msgid="7219575858348719790">"スクリーンセーバー"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"イーサネット"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"機内モード"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"通知を非表示"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"重要な通知のみ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"アラームのみ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"サイレント"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth(端末数<xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"サイレント(アラームも鳴りません)"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"サイレント"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"重要な通知のみ"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"アラームのみ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"次のアラームは<xliff:g id="ALARM_TIME">%s</xliff:g>です"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"次のアラームは<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>です"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g>のアラームは鳴りません"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"ロック解除するには上にスワイプしてください"</string>
     <string name="phone_hint" msgid="3101468054914424646">"右にスワイプして電話を表示"</string>
     <string name="camera_hint" msgid="5241441720959174226">"左にスワイプしてカメラを表示"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"なし"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"重要"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"アラームのみ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"すべて"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"通知\nなし"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"重要な\n通知のみ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"アラーム\nのみ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ユーザーを切り替える"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ユーザーを切り替える、現在のユーザーは<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"許可しない"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>を音量ダイアログとして使用"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"タップすると元の音量ダイアログが復元されます。"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 9de70e8..c405cc2 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ბატარეის დაზოგვის ჩართვა"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"პარამეტრები"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"თვითმფრინავის რეჟიმი"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ავტოროტაციის ეკრანი"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"დადუმება"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ავტო."</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"თვითმფრინავის რეჟიმი ჩაირთო."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ჩართულია რეჟიმი „არ შემაწუხოთ\", მხოლოდ პრიორიტეტები."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ჩართულია რეჟიმი „არ შემაწუხოთ\", შეწყვეტის გარეშე."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"„ნუ შემაწუხებთ“ ჩართულია, მხოლოდ გაფრთხილებები."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"„არ შემაწუხოთ“ გამორთულია"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"„არ შემაწუხოთ\" რეჟიმი გამორთულია."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"„არ შემაწუხოთ\" რეჟიმი ჩართულია."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"სადესერტო ყუთი"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ეთერნეტი"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"თვითმფრინავის რეჟიმი"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"არ შემაწუხოთ"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"მხოლოდ პრიორიტეტული"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"მხოლოდ გაფრთხილებები"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"შეფერხებების გაეშე"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> მოწყობილობა)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"წყვეტების გარეშე. მაღვიძარების შემთხვევაშიც კი."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"შეწყვეტების გარეშე"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"მხოლოდ პრიორიტეტული შეწყვეტები"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"მხოლოდ გაფრთხილებები"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"თქვენი შემდეგი მაღვიძარაა <xliff:g id="ALARM_TIME">%s</xliff:g>-ზე"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"თქვენი შემდეგი მაღვიძარაა <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"თქვენს მაღვიძარას <xliff:g id="ALARM_TIME">%s</xliff:g>-ზე ვერ გაიგონებთ"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"გაასრიალეთ ზევით განსაბლოკად"</string>
     <string name="phone_hint" msgid="3101468054914424646">"გადაფურცლეთ მარჯვნივ ტელეფონისთვის"</string>
     <string name="camera_hint" msgid="5241441720959174226">"კამერისთვის მარცხენა შენაცვლება"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"არცერთი"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"პრიორიტეტი"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"მხოლოდ გაფრთხილებები"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"ყველა"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"არ არის\nშეფერხებები"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"მხოლოდ\nპრიორიტეტულები"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"მხოლოდ\nგაფრთხილებები"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"მომხმარებლის გადართვა"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"მომხმარებლის გდართვა. ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"უარყოფა"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ხმოვან დიალოგშია"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ორიგინალის აღდგენისათვის, შეეხეთ."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index a340624..b6505d5 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Батарея үнемдегішін қосу"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Параметрлер"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Ұшақ режимі"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Авто айналатын экран"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ҮНСІЗ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"Авто"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ұшақ режимі қосылды."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Мазаламау режимі қосулы, тек басымдық"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Мазаламау режимі қосулы, үзілістерсіз"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Кедергі жасамаңыз, тек дабылдар."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Мазаламау режимі өшірулі"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Мазаламау режимі өшірілді."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Мазаламау режимі қосылды."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Десерт жағдайы"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Қалғу"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Ұшақ режимі"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Мазаламау"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Тек басымдық"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Тек дабылдар"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Үзулерсіз"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> құрылғылары)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Үзілулер болмайды. Тіпті дабылдар да."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Үзулерсіз"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Тек басым үзулер"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Тек дабылдар"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Келесі дабыл — <xliff:g id="ALARM_TIME">%s</xliff:g> уақытында"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Келесі дабыл — <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> уақытында дабылды естімейсіз"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Бекітпесін ашу үшін жанаңыз"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Телефон үшін оңға жанаңыз"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Камера үшін солға жанаңыз"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ешқандай"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Басымдық"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Тек дабылдар"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Барлығы"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Кедергілер\nжоқ"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Тек\nбасымдық"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Тек\nдабылдар"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Пайдаланушыны ауыстыру"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Пайдаланушыны ауыстыру, ағымдағы пайдаланушы <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Өшіру"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> — көлем диалогтық терезесі"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Түпнұсқаны қалпына келтіру үшін түртіңіз."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 4fb737c..7df3bcc 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"បើក​ធាតុ​រក្សា​ថាមពល​ថ្ម"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ការ​កំណត់"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"វ៉ាយហ្វាយ"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ពេល​ជិះ​យន្តហោះ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"បង្វិល​អេក្រង់​ស្វ័យ​ប្រវត្តិ"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ស្ងាត់"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ស្វ័យប្រវត្តិ"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"បាន​បើក​របៀប​ជិះ​យន្តហោះ។"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"បានបើកមុខងារកុំរំខាន (អាទិភាពប៉ុណ្ណោះ)។"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"បានបើកមុខងារកុំរំខាន សូមកុំរំខាន"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"មុខងារកុំរំខានបានបើក សម្លេងរោទិ៍ប៉ុណ្ណោះ។"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"បានបិទមុខងារកុំរំខាន។"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"បានបិទមុខងារកុំរំខាន។"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"បានបើកមុខងារកុំរំខាន។"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ករណី Dessert"</string>
     <string name="start_dreams" msgid="7219575858348719790">"ធាតុ​រក្សា​អេក្រង់"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"អ៊ីសឺរណិត"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"របៀបពេល​​ជិះ​យន្តហោះ"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"កុំរំខាន"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"អាទិភាពប៉ុណ្ណោះ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"សំឡេងរោទ៍ប៉ុណ្ណោះ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"សូមកុំរំខាន"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ប៊្លូធូស"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ប៊្លូធូស (ឧបករណ៍ <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"គ្មាន​ការ​ផ្អាក។ គ្មាន​ការ​ជូនដំណឹង​ពី​ព្រឹត្តិការណ៍។"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"គ្មាន​ការ​ផ្អាក"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"តែ​ការ​ផ្អាក​អាទិភាព​ប៉ុណ្ណោះ"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"សំឡេងរោទ៍ប៉ុណ្ណោះ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"ការ​ជូនដំណឹង​បន្ទាប់​របស់​អ្នក​គឺនៅម៉ោង <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ការ​ជូនដំណឹង​បន្ទាប់​របស់​អ្នក​គឺ​នៅ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"អ្នកនឹងមិនឮការជូន​ដំណឹងរបស់អ្នកនៅម៉ោង <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"អូស​ឡើង​លើ ដើម្បី​ដោះ​សោ"</string>
     <string name="phone_hint" msgid="3101468054914424646">"អូស​ទៅ​ស្ដាំ​ដើម្បី​បើក​​ទូរស័ព្ទ"</string>
     <string name="camera_hint" msgid="5241441720959174226">"អូស​ទៅ​ឆ្វេង​​ដើម្បី​ប្រើ​​ម៉ាស៊ីន​ថត"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"គ្មាន"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"អាទិភាព"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"គ្មានការរំខាន"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"អាទិភាពប៉ុណ្ណោះ"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"សំឡេងរោទ៍ប៉ុណ្ណោះ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"ទាំងអស់"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"មិនមានការរំខា\nទេ"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"អាទិភាព\nប៉ុណ្ណោះ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ប្ដូរ​អ្នក​ប្រើ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ប្ដូរ​អ្នកប្រើ ​អ្នកប្រើ​បច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"បដិសេធ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> គឺជាប្រអប់សម្លេង"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ប៉ះដើម្បីស្តារច្បាប់ដើម។"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"រារាំងការរំខាន"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 87a1bb4..e03801a 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ಬ್ಯಾಟರಿ ಉಳಿತಾಯವನ್ನು ಆನ್ ಮಾಡಿ"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ಮ್ಯೂಟ್"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ಸ್ವಯಂ"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್ ಅನ್ನು ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್, ಆದ್ಯತೆ ಮಾತ್ರ."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಆಗಿದೆ, ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"ಅಲಾರಮ್‌‌ಗಳಿಗೆ ಮಾತ್ರ ಅಡಚಣೆ ಮಾಡಬೇಡಿ."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆಫ್ ಆಗಿದೆ."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ತೊಂದರೆ ಮಾಡಬೇಡಿ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ಡೆಸರ್ಟ್ ಕೇಸ್"</string>
     <string name="start_dreams" msgid="7219575858348719790">"ಡೇಡ್ರೀಮ್"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ಇಥರ್ನೆಟ್"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ಏರ್‌ಪ್ಲೇನ್ ಮೋಡ್"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ಆದ್ಯತೆ ಮಾತ್ರ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"ಅಲಾರಮ್‌ಗಳು ಮಾತ್ರ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ಬ್ಲೂಟೂತ್‌"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ಬ್ಲೂಟೂತ್‌ (<xliff:g id="NUMBER">%d</xliff:g> ಸಾಧನಗಳು)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ಅಲಾರಂಗಳನ್ನು ಸೇರಿದಂತೆ ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ಆದ್ಯತೆಯ ಅಡಚಣೆಗಳು ಮಾತ್ರ"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"ಅಲಾರಮ್‌ಗಳು ಮಾತ್ರ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"ನಿಮ್ಮ ಮುಂದಿನ ಅಲಾರಂ <xliff:g id="ALARM_TIME">%s</xliff:g> ಗೆ ಆಗಿದೆ"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ನಿಮ್ಮ ಮುಂದಿನ ಅಲಾರಮ್ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> ಆಗಿದೆ"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> ಗೆ ನೀವು ನಿಮ್ಮ ಅಲಾರಂ ಆಲಿಸುವುದಿಲ್ಲ"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"ಅನ್‌ಲಾಕ್‌ ಮಾಡಲು ಸ್ವೈಪ್‌ ಮಾಡಿ"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ಫೋನ್‌ಗಾಗಿ ಬಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
     <string name="camera_hint" msgid="5241441720959174226">"ಕ್ಯಾಮರಾಗಾಗಿ ಎಡಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ಯಾವುದೂ ಇಲ್ಲ"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ಆದ್ಯತೆ"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"ಯಾವುದೇ ಅಡಚಣೆಗಳಿಲ್ಲ"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"ಆದ್ಯತೆ ಮಾತ್ರ"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"ಅಲಾರಮ್‌ಗಳು ಮಾತ್ರ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"ಎಲ್ಲ"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"ಯಾವುದೇ\nಅಡಚಣೆಗಳಿಲ್ಲ"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ಆದ್ಯತೆ\nಮಾತ್ರ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ಅಲಾರಮ್‌ಗಳು\nಮಾತ್ರ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ, ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ನಿರಾಕರಿಸು"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ವಾಲ್ಯೂಮ್ ಸಂವಾದವಾಗಿದೆ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ಮೂಲ ಮರುಸ್ಥಾಪಿಸಲು ಸ್ಪರ್ಶಿಸಿ."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"ಅಡಚಣೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 884272d..70732cd 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"배터리 절약 기능 사용"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"설정"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"비행기 모드"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"자동 화면 회전"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"무시"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"자동"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"비행기 모드를 사용합니다."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"알림 일시중지 사용, 중요 알림만 수신"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"알림 일시중지 사용, 방해 금지"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"알림 일시중지 사용, 알람만 수신"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"알림 일시중지 사용 중지"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"알림 일시중지가 사용 중지되었습니다."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"알림 일시중지를 사용합니다."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"디저트 케이스"</string>
     <string name="start_dreams" msgid="7219575858348719790">"화면 보호기"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"이더넷"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"비행기 모드"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"알림 일시중지"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"중요 알림만"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"알람만 수신"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"방해 금지"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"블루투스"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"블루투스(<xliff:g id="NUMBER">%d</xliff:g>개의 기기)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"어떤 방해도 받지 않습니다. 알람도 울리지 않습니다."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"모든 알림 차단"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"최우선 알림만 수신"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"알람만 수신"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"다음 알람 시각: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"다음 알람 일시: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g>에 알람을 들을 수 없습니다."</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"위로 스와이프하여 잠금 해제"</string>
     <string name="phone_hint" msgid="3101468054914424646">"전화 기능을 사용하려면 오른쪽으로 스와이프하세요."</string>
     <string name="camera_hint" msgid="5241441720959174226">"카메라를 사용하려면 왼쪽으로 스와이프하세요."</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"수신 안함"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"최우선만 수신"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"알람만 수신"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"모두 수신"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"방해\n금지"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"중요 알림만\n허용"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"알람만\n수신"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"사용자 전환"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"사용자 전환, 현재 사용자 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -370,8 +377,8 @@
     <string name="notification_collapse_button_text" msgid="6883253262134328057">"모두 숨기기"</string>
     <string name="zen_mode_and_condition" msgid="4462471036429759903">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"화면 고정됨"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 뒤로와 개요를 동시에 길게 터치합니다."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 개요를 길게 터치합니다."</string>
+    <string name="screen_pinning_description" msgid="1346522416878235405">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 뒤로와 최근 사용을 동시에 길게 터치합니다."</string>
+    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치합니다."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"확인"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"거부"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"거부"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 볼륨 대화입니다."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"원본을 복원하려면 터치하세요."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 1a7aa8b..9aa2703 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -52,8 +52,6 @@
     <skip />
     <!-- no translation found for status_bar_settings_wifi_button (1733928151698311923) -->
     <skip />
-    <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
-    <skip />
     <!-- no translation found for status_bar_settings_auto_rotation (3790482541357798421) -->
     <skip />
     <!-- no translation found for status_bar_settings_mute_label (554682549917429396) -->
@@ -206,6 +204,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Учак режими күйгүзүлдү."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Тынчымды алба деген күйүк, артыкчылыктуулар гана."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Тынчымды алба деген күйүк, үзгүлтүккө учуратуулар жок."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Тынчымды алба деген күйүк, ойготкучтар гана."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Тынчымды алба деген өчүк."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Тынчымды алба деген өчүрүлдү."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Тынчымды алба деген күйгүзүлдү."</string>
@@ -256,9 +255,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Десерт себети"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Кыялдануу"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Учак тартиби"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Тынчымды алба"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Артыкчылык гана"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Ойготкучтар гана"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Үзгүлтүксүз"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> түзмөк)"</string>
@@ -329,6 +328,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Үзгүлтүктөр жок. Ойготкучтар дагы жок."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Үзгүлтүксүз"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Артыкчылыктуу үзгүлтүктөр гана"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Ойготкучтар гана"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Кийинки үн ишараты саат <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Кийинки үн ишараты <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Саат <xliff:g id="ALARM_TIME">%s</xliff:g> үн ишаратын укпайсыз."</string>
@@ -338,9 +338,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Кулпуну ачуу үчүн серпип коюңуз"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Телефонду колдонуу үчүн оңго серпип коюңуз"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Камераны ачуу үчүн солго серпип коюңуз"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Эч нерсе жок"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Артыкчылыктуу"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Ойготкучтар гана"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Бардыгы"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Үзгүтүк\nжок"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Колдонуучуну которуу"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Колдонуучуну күйгүзүү, учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -408,4 +414,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Жок"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> үндү катуулатуу диалогу"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Түпнусканы калыбына келтирүү үчүн тийип коюңуз."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index e58fbb1..8919198 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -18,10 +18,4 @@
     <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer">
         <item name="android:layout_width">360dp</item>
     </style>
-
-    <style name="SearchPanelScrim">
-        <item name="android:layout_width">@dimen/search_panel_scrim_height</item>
-        <item name="android:layout_height">match_parent</item>
-        <item name="android:layout_gravity">right</item>
-    </style>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 4d215e3..18dc348 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"​ເປີດ​ໃຊ້​ໂຕ​ປະ​ຢັດ​ແບັດ​ເຕີ​ຣີ"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ການຕັ້ງຄ່າ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ໂໝດເທິງຍົນ"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ປິດສຽງ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ອັດຕະໂນມັດ"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ເປີດ​ໂໝດ​ຢູ່​ໃນ​ຍົນ​ແລ້ວ."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ຫ້າມ​ລະ​ກວນ​ເປີດ​ຢູ່, ບຸ​ລິ​ມະ​ສິດ​ເທົ່າ​ນັ້ນ."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ຫ້າມ​ລະ​ກວນ​ເປີດ​ຢູ່, ບໍ່​ມີ​ການ​ຂັດ​ຈັງ​ຫວະ."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"ຫ້າມ​ລົບ​ກວນ​ເປີດ​ຢູ່, ໂມງ​ປຸກ​ເທົ່າ​ນັ້ນ."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ຫ້າມ​ລົບ​ກວນປິດຢູ່."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ຢ່າ​ລົບ​ກວນ​ປິດ​ແລ້ວ."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ຢ່າ​ລົບ​ກວນ​ເປີດ​ແລ້ວ."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ກ່ອງຂອງຫວານ"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ໂໝດຢູ່ໃນຍົນ"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ຫ້າມ​ລົບ​ກວນ"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ບຸ​ລິ​ມະ​ສິດເທົ່າ​ນັ້ນ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"ໂມງ​ປຸກ​ເທົ່າ​ນັ້ນ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ບໍ່​ມີ​ການ​ລົບກວນ"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ອຸປະກອນ)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ບໍ່​ມີ​ການ​ລົບ​ກວນ. ບໍ່​ວ່າ​ຈະ​ເປັນ​​ໂມງ​ປຸກ​ກໍ​ຕາມ."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"ບໍ່​ມີ​ການ​ລົບກວນ"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ສະເພາະ​ເລື່ອງ​ສຳຄັນ​ເທົ່ານັນ"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"ໂມງ​ປຸກ​ເທົ່າ​ນັ້ນ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"ໂມງ​ປຸກ​ຖັດ​ໄປ​ຂອງ​ທ່ານ​ແມ່ນ <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ໂມງ​ປຸກ​ຖັດ​ໄປ​ຂອງ​ທ່ານ​ແມ່ນ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"ທ່ານ​ຈະ​ບໍ່​ໄດ້​ຍິນ​ສຽງ​ໂມງ​ປຸກ​ໃນ​ເວ​ລາ <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"ເລື່ອນ​ຂຶ້ນ​ເພື່ອ​ປົດ​ລັອກ"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ປັດ​ຂວາ​ເພື່ອ​ໃຊ້​ໂທ​ລະ​ສັບ"</string>
     <string name="camera_hint" msgid="5241441720959174226">"ປັດ​ຊ້າຍ​ເພື່ອ​ໃຊ້​ກ້ອງ"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ບໍ່ມີ"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ລະດັບຄວາມສຳຄັນ"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"ບໍ່​ມີ​ການ​ລົບກວນ"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"ບຸ​ລິ​ມະ​ສິດເທົ່າ​ນັ້ນ"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"ໂມງ​ປຸກ​ເທົ່າ​ນັ້ນ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"ທັງໝົດ"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"ບໍ່​ມີ\nລົບ​ກວນ"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ສະ​ລັບ​ຜູ່ໃຊ້"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ປ່ຽນຜູ່ໃຊ້, ຜູ່ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ປະຕິເສດ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ແມ່ນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ສໍາ​ຜັດ​ເພື່ອກູ້​ຄືນ​ຕົ້ນ​ສະ​ບັບ​."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"ບ​ລັອກ​ການ​ລົບ​ກວນ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 1cb5980..2832015 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Įj. Akum. tausojimo priemonę"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nustatymai"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lėktuvo režimas"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatiškai sukti ekraną"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"NUTILD."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lėktuvo režimas įjungtas."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Funkcija „Netrukdyti“ įjungta. Tik prioritetiniai įvykiai."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Funkcija „Netrukdyti“ įjungta. Jokių pertraukčių."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Funkcija „Netrukdyti“ įjungta. Leidžiami tik signalai."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Funkcija „Netrukdyti“ išjungta."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Funkcija „Netrukdyti“ išjungta."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Funkcija „Netrukdyti“ įjungta."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Desertų dėklas"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Svajonė"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Eternetas"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lėktuvo režimas"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Netrukdyti"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tik prioritetiniai įvykiai"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Tik signalai"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Jokių pertraukčių"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"„Bluetooth“ (<xliff:g id="NUMBER">%d</xliff:g> įreng.)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Nėra trikdžių. Nėra net įspėjimų."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Jokių pertraukčių"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Tik prioritetinės pertrauktys"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Tik signalai"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Kito signalo laikas: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Kito signalo laikas: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> signalo negirdėsite"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Perbraukite aukštyn, kad atrakintumėte"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Perbraukite į dešinę, kad galėtumėte skambinti"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Perbraukite į kairę, kad būtų įjungtas fotoaparatas"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nėra"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritetas"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Tik signalai"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Visi"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Neleidžiama\ntrukdyti"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tik\nprioritetiniai"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tik\nsignalai"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Perjungti naudotoją"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Perjungti naudotoją, dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Atmesti"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ yra garsumo valdymo dialogo langas"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Palieskite, kad atkurtumėte originalą."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5fdc0cd..34e4da00 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -45,7 +45,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Ieslēgt akumulatora jaudas taupīšanu"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Iestatījumi"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Lidmašīnas režīms"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automātiska ekrāna pagriešana"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"IZ. SK."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
@@ -181,6 +180,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Lidojuma režīms ir ieslēgts."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Statuss Netraucēt ir ieslēgts, izvēlēts iestatījums Tikai prioritārie."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Statuss Netraucēt ir ieslēgts, izvēlēts iestatījums Bez pārtraukumiem."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Ieslēgts režīms “Netraucēt”, atļauti tikai signāli."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Statuss Netraucēt ir izslēgts."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Statuss Netraucēt tika izslēgts."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Statuss Netraucēt tika ieslēgts."</string>
@@ -231,9 +231,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Saldo ēdienu stends"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Ekrānsaudzētājs"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Tīkls Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Lidojuma režīms"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Netraucēt"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tikai prioritārie"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Tikai signāli"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Bez pārtraukumiem"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> ierīce(-es))"</string>
@@ -304,6 +304,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Bez traucējumiem. Pat bez brīdinājumiem"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Nepārtraukt"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Tikai prioritārie pārtraukumi"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Tikai signāli"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Jūsu nākamā signāla laiks: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Jūsu nākamā signāla datums un laiks: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Jūs nedzirdēsiet iestatīto signālu: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -313,9 +314,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Velciet uz augšu, lai atbloķētu"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Lai lietotu tālruni, velciet pa labi."</string>
     <string name="camera_hint" msgid="5241441720959174226">"Lai lietotu kameru, velciet pa kreisi."</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nav"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritāte"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Tikai signāli"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Visi"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Nepārtraukt\n"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tikai\nprioritārie"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tikai\nsignāli"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mainīt lietotāju"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Pārslēgt lietotāju; pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -383,4 +390,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Neatļaut"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ir skaļuma dialoglodziņš"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Pieskarieties, lai atjaunotu sākotnējo."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 83988c0..b0ba780 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Вклучете го штедачот на батерија"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подесувања"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим на работа во авион"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоматско ротирање на екранот"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ИСКЛ."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"Автоматски"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Авионскиот режим е вклучен."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"„Не вознемирувај“ е вклучено, само приоритетни."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"„Не вознемирувај“ е вклучено, без прекини."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"„Не вознемирувај“ е вклучено, само аларми."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"„Не вознемирувај“ е исклучено."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"„Не вознемирувај“ е исклучено."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"„Не вознемирувај“ е вклучено."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим на работа во авион"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не вознемирувај"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Само приоритетно"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Само аларми"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без прекини"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уреди)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Без прекини. Дури и без аларми."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Без прекини"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Само приоритетни прекини"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Само аларми"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Следниот аларм е во <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Следниот аларм е <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Нема да го слушнете алармот во <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Повлечете за да се отклучи"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Повлечете надесно за телефон"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Повлечете налево за камера"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ништо"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Приоритет"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Само аларми"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Сѐ"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Нема\nпрекини"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприоритетни"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Промени го корисникот"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промени го корисникот, тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Одбиј"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> е дијалог за јачина на звук"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Допрете за да го вратите оригиналот."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index ee090f9..fb9fa0e 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ബാറ്ററി സേവർ ഓണാക്കുക"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ക്രമീകരണങ്ങൾ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ഫ്ലൈറ്റ് മോഡ്"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"സ്‌ക്രീൻ യാന്ത്രികമായി തിരിക്കുക"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"മ്യൂട്ടുചെയ്യുക"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"യാന്ത്രികം"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ഫ്ലൈറ്റ് മോഡ് ഓണാക്കി."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാണ്, മുൻഗണന മാത്രം."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാണ്, തടസ്സങ്ങളൊന്നുമില്ല."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\'ശല്യപ്പെടുത്തരുത്\' ഓണാണ്, അലാറം മാത്രം."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ശല്ല്യപ്പെടുത്തരുത് എന്നത് ഓഫാണ്."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓഫാക്കി."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ശല്യപ്പെടുത്തരുത് എന്നത് ഓണാക്കി."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ഡെസേർട്ട് കെയ്സ്"</string>
     <string name="start_dreams" msgid="7219575858348719790">"ഡേഡ്രീം"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ഇതർനെറ്റ്"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ഫ്ലൈറ്റ് മോഡ്"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ശല്ല്യപ്പെടുത്തരുത്"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"മുൻഗണന മാത്രം"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"അലാറങ്ങൾ മാത്രം"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"തടസ്സങ്ങളൊന്നുമില്ല"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ബ്ലൂടൂത്ത്"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ബ്ലൂടൂത്ത് (<xliff:g id="NUMBER">%d</xliff:g> ഉപകരണങ്ങൾ)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"തടസ്സങ്ങളൊന്നുമില്ല. അലാറങ്ങൾ പോലുമില്ല."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"തടസ്സങ്ങളൊന്നുമില്ല"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"മുൻഗണനാ തടസ്സങ്ങൾ മാത്രം"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"അലാറങ്ങൾ മാത്രം"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"നിങ്ങളുടെ അടുത്ത അലാറം <xliff:g id="ALARM_TIME">%s</xliff:g>-നാണ്"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"നിങ്ങളുടെ അടുത്ത അലാറം <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>-നാണ്"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"നിങ്ങൾ <xliff:g id="ALARM_TIME">%s</xliff:g>-ന് അലാറം കേൾക്കില്ല"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"അൺലോക്കുചെയ്യുന്നതിന് മുകളിലേക്ക് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ഫോണിനായി വലതുവശത്ത് സ്വൈപ്പുചെയ്യുക"</string>
     <string name="camera_hint" msgid="5241441720959174226">"ക്യാമറയ്‌ക്കായി ഇടതുവശത്ത് സ്വൈപ്പുചെയ്യുക"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ഒന്നുമില്ല"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"പ്രധാനപ്പെട്ടവ"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"തടസ്സങ്ങളൊന്നുമില്ല"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"മുൻഗണന മാത്രം"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"അലാറങ്ങൾ മാത്രം"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"എല്ലാം"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"തടസ്സങ്ങൾ\nഒന്നുമില്ല"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"മുൻഗണന\nമാത്രം"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"അലാറങ്ങൾ\nമാത്രം"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ഉപയോക്താവ് മാറുക"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ഉപയോക്താവിനെ മാറ്റുക, <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> എന്നയാളാണ് നിലവിലുള്ള ഉപയോക്താവ്"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"നിരസിക്കുക"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗാണ്"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"ആദ്യത്തേത് പുനഃസ്ഥാപിക്കാൻ സ്‌പർശിക്കുക."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"തടസ്സങ്ങൾ തടയുക"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 66f287a..b558cfa 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -42,7 +42,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Батерей хэмнэгчийг асаах"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Тохиргоо"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Нислэгийн горим"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Дэлгэцийг автоматаар эргүүлэх"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ХААХ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТОМАТ"</string>
@@ -178,6 +177,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Нислэгийн горимыг асаасан."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Бүү саад болно уу.Зөвхөн чухал зүйлст."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Бүү саад болно уу. Аливаа саад учруулахгүй байна уу."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Бүү саад бол, зөвхөн сэрүүлгийг асаа."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Бүү саад бол."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Идэвхгүй болгох үйлдэлд бүү саад бол."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Идэвхжүүлэх үйлдэлд бүү саад бол."</string>
@@ -228,9 +228,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Амттаны хайрцаг"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Этернет"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Нислэгийн горим"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Бүү саад бол"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Зөвхөн чухал зүйлс"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Зөвхөн сэрүүлэг"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Аливаа саад байхгүй байх"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Блютүүт"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Блютүүт (<xliff:g id="NUMBER">%d</xliff:g> төхөөрөмж)"</string>
@@ -301,6 +301,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Тасалдал байхгүй. Сэрүүлэг ч байхгүй."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Ямар ч тасалдалгүй"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Зөвхөн нэн тэргүүний тасалдалд"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Зөвхөн сэрүүлэг"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Таны дараагийн сэрүүлгийн цаг <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Таны дараагийн сэрүүлгийн цаг <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Та <xliff:g id="ALARM_TIME">%s</xliff:g>-д өөрийн сэрүүлгээ сонсохгүй"</string>
@@ -310,9 +311,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Түгжээг тайлах бол шудрана уу"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Утас гаргахын тулд баруун шударна уу"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Камер гаргахын тулд зүүн шударна уу"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Хоосон"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Нэн тэргүүний"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Аливаа саад байхгүй байх"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Зөвхөн чухал зүйлс"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Зөвхөн сэрүүлэг"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Бүгд"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Ямар ч\nтасалдал байхгүй"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Зөвхөн\nхамгийн чухлыг"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Зөвхөн\nсэрүүлэг"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Хэрэглэгчийг сэлгэх"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Хэрэглэгчийг сэлгэх, одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -380,4 +385,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Татгалзах"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог юм."</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Анхны хувилбарыг эргүүлэн хадгалахыг хүсвэл хүрнэ үү."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Тасалдуулахгүй байх"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index f40429c..77f8348 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"बॅटरी बचतकर्ता चालू करा"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिंग्ज"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाय-फाय"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"विमान मोड"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वयं-फिरणारी स्क्रीन"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"नि:शब्द करा"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वयं"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"विमान मोड चालू केला."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"व्यत्यय आणू नका चालू, केवळ प्राधान्य."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"व्यत्यय आणू नका चालू, कोणताही व्यत्यय नाही."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"व्यत्यय आणू नका चालू, केवळ अलार्म."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"व्यत्यय आणू नका बंद."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"व्यत्यय आणू नका बंद करा"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"व्यत्यय आणू नका चालू करा"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"मिष्ठान्न प्रकरण"</string>
     <string name="start_dreams" msgid="7219575858348719790">"डेड्रीम"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"इथरनेट"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"विमान मोड"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"व्यत्यय आणू नका"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"केवळ प्राधान्य"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"केवळ अलार्म"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"कोणतेही व्यत्यय नाही"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लूटुथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब (<xliff:g id="NUMBER">%d</xliff:g> डिव्हाइसेस)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"कोणतेही व्यत्यय नाहीत. अगदी अलार्मचे देखील नाहीत."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"कोणतेही व्यत्यय नाही"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"केवळ प्राधान्य दिलेले व्‍यत्यय"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"केवळ अलार्म"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"आपला पुढील अलार्म <xliff:g id="ALARM_TIME">%s</xliff:g> वाजता आहे"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"आपला पुढील अलार्म <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> आहे"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"आपण आपला अलार्म <xliff:g id="ALARM_TIME">%s</xliff:g> वाजता ऐकणार नाही"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलॉक करण्यासाठी स्वाइप करा"</string>
     <string name="phone_hint" msgid="3101468054914424646">"फोन साठी उजवीकडे स्वाइप करा"</string>
     <string name="camera_hint" msgid="5241441720959174226">"कॅमेर्‍यासाठी डावीकडे स्वाइप करा"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"काहीही नाही"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"प्राधान्य"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"कोणतेही व्यत्यय नाहीत"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"केवळ प्राधान्य"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"केवळ अलार्म"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"सर्व"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"कोणतेही व्यत्यय\nनाही"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवळ\nप्राधान्य"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवळ\nअलार्म"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"वापरकर्ता स्विच करा"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"वापरकर्ता स्विच करा, वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"नकार द्या"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा व्हॉल्यूम संवाद आहे"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूळ पुनर्संचयित करण्यासाठी स्पर्श करा."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"व्यत्यय अवरोधित करा"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 5ee867f..db43a54 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Hidupkan penjimat bateri"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Tetapan"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod pesawat"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autoputar skrin"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"REDAM"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Mod pesawat dihidupkan."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Jangan ganggu dihidupkan, perkara penting sahaja."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Jangan ganggu dihidupkan, tiada gangguan."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Jangan ganggu dihidupkan, penggera sahaja."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Jangan ganggu dimatikan."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Jangan ganggu dimatikan."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Jangan ganggu dihidupkan."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Bekas Pencuci Mulut"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Lamun"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod kapal terbang"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Jangan ganggu"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Keutamaan sahaja"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Penggera sahaja"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Tiada gangguan"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Peranti)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Tiada gangguan, walau penggera sekalipun."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Tiada gangguan"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Gangguan keutamaan sahaja"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Penggera sahaja"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Penggera anda yang seterusnya pada <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Penggera anda yang seterusnya pada <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Anda tdk akan mdgr penggera anda pd <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Leret ke atas untuk membuka kunci"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Leret ke kanan untuk telefon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Leret ke kiri untuk kamera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Tiada"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Keutamaan"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Tiada gangguan"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Keutamaan sahaja"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Penggera sahaja"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Semua"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Tiada\ngangguan"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Keutamaan\nsahaja"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Penggera\nsahaja"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Tukar pengguna"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Tukar pengguna, pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tolak"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ialah dialog kelantangan"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Sentuh untuk memulihkan yang asal."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Halang gangguan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 8880f93..e792a58 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ဘက်ထရီ ချွေတာမှုကို ဖွင့်ရန်"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"အပြင်အဆင်များ"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"ဝိုင်ဖိုင်"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"လေယာဥ်ပျံပေါ်အသုံးပြုသောစနစ်"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"မျက်နှာပြင်အလိုအလျောက်လှည့်ရန်"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"လေယာဉ် မုဒ်ကို ဖွင့်ထားလိုက်ပြီ။"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"မနှောင့်ယှက်ပါနှင့် ဖွင့်ထားသည်၊ ဦးစားပေးများသာ။"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"မနှောင့်ယှက်ပါနှင့် ဖွင့်ထားသည်၊ အနှောင့်အယှက်များ မရှိပါ။"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"အနှောင့်ယှက်ရ ဖွင့်ထားသည်။ နှိုးစက်များသာ။"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"မနှောင့်ယှက်ပါနှင့် ကိုပိတ်ထားသည်။"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"မနှောင့်ယှက်ပါနှင့် ကိုပိတ်ထားသည်။"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"မနှောင့်ယှက်ပါနှင့်ကို ဖွင့်ထားသည်။"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"မုန့်ထည့်သော ပုံး"</string>
     <string name="start_dreams" msgid="7219575858348719790">"ဒေးဒရင်းမ်"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"အီသာနက်"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"လေယာဥ်ပျံပေါ်အသုံးပြုသောစနစ်"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"မနှောက်ယှက်ပါနှင့်"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ဦးစားပေးများသာ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"နှိုးစက်များသာ"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ကြားဖြတ်ဝင်မှု ခွင့်မပြုရန်"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ဘလူးတု"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ဘလူးတု (<xliff:g id="NUMBER">%d</xliff:g> စက်များ)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ကြားဖြတ်ဝင်မှုများ မရှိခဲ့။ နှိုးစက်ပင် မရှိခဲ့။"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"ကြားဖြတ်ဝင်မှု ခွင့်မပြုရန်"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ဦးစားပေး ကြားဖြတ်ဝင်မှုများ သာလျှင်"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"နှိုးစက်များသာ"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"သင်၏ နောက် နှိုးစက်၏ အချိန်မှာ<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"သင်၏ နောက် နှိုးစက်မှာ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"သင်သည် သင်၏ <xliff:g id="ALARM_TIME">%s</xliff:g> နှိုးစက်ကို ကြားရမည် မဟုတ်"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"သော့ဖွင့်ရန် အပေါ်သို့ ပွတ်ဆွဲပါ"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ဖုန်း အတွက် ညာသို့ ပွတ်ဆွဲပါ"</string>
     <string name="camera_hint" msgid="5241441720959174226">"ကင်မရာ အတွက် ဘယ်သို့ ပွတ်ဆွဲပါ"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"မရှိ"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ဦးစားပေးမှု"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"ကြားဖြတ်ဝင်မှု ခွင့်မပြုရန်"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"ဦးစားပေးများသာ"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"နှိုးစက်များသာ"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"အားလုံး"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">\n"ကြားဝင်မှု မရှိပါ"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ဦးစားပေးမှု\nသာ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"နှိုးစက်များ\nသာ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"အသုံးပြုသူကို ပြောင်းရန်၊ လက်ရှိ အသုံးပြုသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ငြင်းပယ်သည်"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် အသံဒိုင်ယာလော့ခ်ဖြစ်သည်"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"မူရင်းအားပြန်လည်သိမ်းဆည်းရန် ထိပါ။"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"ကြားဖြတ်ဝင်မှုများ ပိတ်ဆို့ရန်"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 07cf096..26e6cad 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Slå på batterisparing"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Innstillinger"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Trådløse nettverk"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flymodus"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Roter skjerm automatisk"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPET"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flymodus er slått på."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"«Ikke forstyrr» er på – bare prioritert."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"«Ikke forstyrr» er på – ingen avbrytelser."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Ikke forstyrr er på – bare alarmer."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"«Ikke forstyrr» er av."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"«Ikke forstyrr» er slått av."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"«Ikke forstyrr» er slått på."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertmonter"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flymodus"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"«Ikke forstyrr»"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Bare prioritet"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Bare alarmer"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Ingen forstyrrelser"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Ingen forstyrrelser, ikke engang alarmer."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Ingen forstyrrelser"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Bare prioriterte forstyrrelser"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Bare alarmer"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Den neste alarmen din er stilt inn kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Den neste alarmen din er stilt inn <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Du kommer ikke til å høre alarmen kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Sveip oppover for å låse opp"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Sveip mot høyre for å åpne telefonen"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Sveip mot venstre for å åpne kameraet"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ingen"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritet"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Bare alarmer"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Ingen\nforstyrrelser"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Bare\nPrioritet"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Bare\nalarmer"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Bytt bruker"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Bytt bruker, gjeldende bruker er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Ikke tillat"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> er volumdialogen"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Trykk for å gå tilbake til den opprinnelige volumdialogen."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 549bc8b..edabd65 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"ब्याट्री बचत खोल्नुहोस्"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"सेटिङहरू"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"वाइफाइ"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"हवाइजहाज मोड"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"स्वत:घुम्ने स्क्रिन"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"म्युट गर्नुहोस्"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"स्वतः"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"हवाइजहाज मोड खोलियो।"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"प्राथमिकतालाई मात्र बाधा नपुर्‍याउनुहोस्।"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"बाधा नपुर्याउँनुहोस्, कुनै पनि अवरोध छैनन्।"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"बाधा नगर्नुहोस्, आलार्महरू मात्र।"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"निष्क्रियलाई बाधा नपुर्‍याउनुहोस्"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"निष्क्रिय गरिएकालाई अवरोध नपुर्‍याउनुहोस्।"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"सक्रिय रहेकोलाई अवरोध नपुर्‍याउनुहोस्।"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"दिवासपना"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"हवाइजहाज मोड"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"बाधा नपुर्याउँनुहोस्"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"प्राथमिकता मात्र"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"अलार्महरू मात्र"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"कुनै अवरोधहरू छैन"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"ब्लुटुथ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"ब्लुटुथ (<xliff:g id="NUMBER">%d</xliff:g> उपकरणहरू)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"कुनै रुकावट छैन। चेतावनी समेत छैन।"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"कुनै रुकावटहरू छैन"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"प्राथमिकता रुकावटहरूमा मात्र"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"अलार्महरू मात्र"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"तपाईंको अर्को सचेतक <xliff:g id="ALARM_TIME">%s</xliff:g> मा छ"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"तपाईंको अर्को सचेतक <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> हो"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> मा तपाईंले आफ्नो सचेतक सुन्नुहुने छैन"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"अनलक गर्न स्वाप गर्नुहोस्"</string>
     <string name="phone_hint" msgid="3101468054914424646">"फोनका लागि दाँया स्वाइप"</string>
     <string name="camera_hint" msgid="5241441720959174226">"क्यामेराका लागि बाँया स्वाइप"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"कुनै पनि होइन"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"प्राथमिकता"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"कुनै अवरोधहरू छैनन्"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"प्राथमिकता मात्र"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"अलार्महरू मात्र"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"सबै"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">\n" रोकावटहरू छैनन्"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"प्राथमिकता \nमात्र"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"आलार्महरू \nमात्र"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"प्रयोगकर्ता फेर्नुहोस्"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"प्रयोगकर्ता, हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> मा स्विच गर्नुहोस्"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार गर्नुहोस्"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> भोल्यूम संवाद हो"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल पुनर्स्थापना गर्न छुनुहोस्।"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"अवरोधहरू रोक्नुहोस्"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 4f2bcc5..0959bff 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Accubesparing inschakelen"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Instellingen"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wifi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Vliegtuigmodus"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Scherm automatisch draaien"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEMPEN"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Vliegtuigmodus ingeschakeld."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Niet storen aan, alleen prioriteit."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Niet storen aan, geen onderbrekingen."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Niet storen aan, alleen alarmen."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Niet storen uit."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Niet storen uitgeschakeld."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Niet storen ingeschakeld."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertshowcase"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdroom"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Vliegtuigmodus"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Niet storen"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Alleen prioriteit"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Alleen alarmen"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Geen onderbrekingen"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> apparaten)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Geen onderbrekingen. Zelfs geen alarm."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Geen onderbrekingen"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Alleen prioriteitsonderbrekingen"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Alleen alarmen"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Uw volgende alarm is om <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Uw volgende alarm is <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"U hoort uw alarm niet om <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Veeg omhoog om te ontgrendelen"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Veeg naar rechts voor telefoon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Veeg naar links voor camera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Geen"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioriteit"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Alleen alarmen"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Alle"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Geen\nonderbrekingen"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Gebruiker wijzigen"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schakelen tussen gebruikers, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Afwijzen"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> is het volumedialoogvenster"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tik hierop om het origineel te herstellen."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 7e7253c..0680ce2 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Włącz oszczędzanie baterii"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ustawienia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Tryb samolotowy"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Autoobracanie ekranu"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"WYGAŚ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Tryb samolotowy został włączony."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Nie przeszkadzać (włączone, tylko priorytetowe)."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Nie przeszkadzać (włączone, bez przeszkadzania)."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Nie przeszkadzać (włączone, tylko alarmy)."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Nie przeszkadzać (wyłączone)."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Nieprzeszkadzanie wyłączone."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Nieprzeszkadzanie włączone."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Półka ze słodkościami"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Wygaszacz ekranu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Tryb samolotowy"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nie przeszkadzać"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Tylko priorytetowe"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Tylko alarmy"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Bez przeszkadzania"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (urządzenia: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Żadnych powiadomień. Nawet alarmów."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Bez przerw"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Tylko dźwięki priorytetowe"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Tylko alarmy"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Następny alarm o <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Następny alarm: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Nie usłyszysz alarmu o <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Przesuń w górę, by odblokować"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Przesuń w prawo, by przełączyć się na telefon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Przesuń w lewo, by włączyć aparat"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Żadne"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Priorytetowe"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Tylko alarmy"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Wszystkie"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">\n"0/}przeszkadzać"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tylko\npriorytetowe"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tylko\nalarmy"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Przełącz użytkownika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Przełącz użytkownika. Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmów"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> steruje głośnością"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Dotknij, by przywrócić pierwotną."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 14f60dc..891ff16 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Ativar a poupança de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Definições"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo de avião"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rodar ecrã automaticamente"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"D. SOM"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modo de avião ligado."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Não incomodar ligado, apenas prioridade."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Não incomodar ligado, sem interrupções."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Não incomodar ligado, apenas alarmes."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Não incomodar desligado."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Não incomodar desligado."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Não incomodar ligado."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Vitrina de sobremesas"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo de avião"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Não incomodar"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Apenas prioridade"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Apenas alarmes"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sem interrupções"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Dispositivos)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Sem interrupções. Nem mesmo alarmes."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Sem interrupções"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Apenas interrupções com prioridade"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Apenas alarmes"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"O próximo alarme é à(s) <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"O próximo alarme é <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Não vai ouvir o alarme à(s) <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslizar rapidamente com o dedo para cima para desbloquear"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Deslize rapidamente para a direita para aceder ao telemóvel"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Deslize rapidamente para a esquerda para aceder à câmara"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nenhum"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioridade"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Apenas alarmes"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Sem\ninterrupções"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Apenas\nprioridade"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Apenas\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mudar utilizador"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Mudar de utilizador; o utilizador atual é <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Recusar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo do volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 15d869a..a0e80e6 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Ativar a economia de bateria"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Configurações"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Modo avião"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Girar automaticamente a tela"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUDO"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"O modo avião foi ativado."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Não perturbe\" ativado, somente prioridade."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Não perturbe\" ativado, sem interrupções."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Não perturbe\" ativado, somente alarmes."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Não perturbe\" desativado."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Não perturbe\" desativado."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Não perturbe\" ativado."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Mostruário de sobremesas"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Modo avião"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Não perturbe"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Só prioridade"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Somente alarmes"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Sem interrupções"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispositivos)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Sem interrupções. Nem mesmo alarmes."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Sem interrupções"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Apenas interrupções prioritárias"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Somente alarmes"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Seu próximo alarme será às <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Seu próximo alarme será em <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Você não ouvirá o alarme às <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Deslize para cima para desbloquear"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Deslize à direita p/ usar o telefone"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Deslize à esquerda p/ usar a câmera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nenhum"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioridade"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Sem interrupções"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Só prioridade"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Somente alarmes"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tudo"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Sem\ninterrupções"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +389,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Negar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é a caixa de diálogo referente ao volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toque para restaurar o original."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Bloquear interrupções"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d517a42..100f8e7 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -45,7 +45,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Activați economisirea bateriei"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Setări"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Mod Avion"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotire automată a ecranului"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"DEZAC."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTOM."</string>
@@ -181,6 +180,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modul Avion este activat."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Setarea „Nu deranja” este activată – numai prioritare."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Setarea „Nu deranja” este activată – fără întreruperi."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Setarea „Nu deranja” este activată – numai alarme."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Setarea „Nu deranja” este dezactivată."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Setarea „Nu deranja” a fost dezactivată."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Setarea „Nu deranja” a fost activată."</string>
@@ -231,9 +231,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Vitrina cu dulciuri"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Mod Avion"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nu deranja"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Numai cu prioritate"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Numai alarme"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Fără întreruperi"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> dispozitive)"</string>
@@ -304,6 +304,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Fără întreruperi. Nici măcar alarme."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Fără întreruperi"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Numai întreruperi cu prioritate"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Numai alarme"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Următoarea alarmă este setată la <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Următoarea alarmă este la <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Nu veți auzi alarma la <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -313,9 +314,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Glisați în sus pentru a debloca"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Glisați la dreapta pentru a acesa telefonul"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Glisați la stânga pentru a accesa camera foto"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Niciuna"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritate"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Numai alarme"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Toate"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Fără\nîntreruperi"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Numai\ncu prioritate"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Numai\nalarme"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Comutați între utilizatori"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schimbați utilizatorul (utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -383,4 +390,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Refuzați"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> afișează caseta de dialog pentru volum"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Atingeți pentru a reveni la setarea inițială."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index b53b581..18ebf13 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Включить режим энергосбережения"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Настройки"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим полета"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Автоповорот экрана"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ВЫКЛ."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТО"</string>
@@ -184,6 +183,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим полета включен."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Режим \"Не беспокоить\" включен. Будут показаны только важные оповещения."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Включен режим \"Не беспокоить\". Все оповещения отключены."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Не беспокоить – только будильник."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Режим \"Не беспокоить\" выключен."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Режим \"Не беспокоить\" выключен."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Режим \"Не беспокоить\" включен."</string>
@@ -234,9 +234,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Коробка со сладостями"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Заставка"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим полета"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не беспокоить"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Только важные"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Только будильник"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без оповещений"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -307,6 +307,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Никаких оповещений, даже от будильника."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Не беспокоить"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Только важные оповещения"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Только будильник"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Следующий будильник: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Следующий будильник: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Следующий будильник: <xliff:g id="ALARM_TIME">%s</xliff:g>. Звук отключен."</string>
@@ -316,9 +317,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Проведите вверх, чтобы разблокировать"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Чтобы позвонить, пролистните вправо"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Чтобы включить камеру, пролистните влево"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Не беспокоить"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Важные"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Только будильник"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Все"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Без\nпрерываний"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Только\nважные"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Только\nбудильник"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Сменить пользователя."</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Сменить аккаунт. Вход выполнен под именем <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>."</string>
@@ -386,4 +393,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Нет"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> назначено регулятором громкости"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Нажмите, чтобы восстановить приложение по умолчанию."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 8bf3a29..d3b1044 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"බැටරි සුරැකීම සක්‍රිය කරන්න"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"සැකසීම්"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"අහස්යානා ආකාරය"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"නිශ්ශබ්ද කරන්න"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"ස්වයංක්‍රීය"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"අහස්යානා ආකාරය සක්‍රීයයි."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"බාධා නොකරන්න ක්‍රියාත්මකයි, ප්‍රමුඛතා පමණි."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"බාධා නොකරන්න ක්‍රියාත්මකයි, බාධා කිරීම් නැත."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"බාධා නොකරන්න ක්‍රියාත්මකයි, ප්‍රමුඛතා පමණි."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"බාධා නොකරන්න ක්‍රියා විරහිතයි."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"බාධා නොකරන්න ක්‍රියා විරහිත කරන ලදි."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"බාධා නොකරන්න ක්‍රියාත්මක කරන ලදි"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"අතුරුපස අවස්තාව"</string>
     <string name="start_dreams" msgid="7219575858348719790">"දවල් හීනය"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ඊතර නෙට්"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"අහස්යානා ආකාරය"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"බාධා නොකරන්න"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ප්‍රමුඛතාව පමණයි"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"ඇඟවීම් පමණි"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"බාධා කිරීම් නැත"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"බ්ලූටූත්"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"බ්ලූටූත් (උපාංග <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"අතුරු බිඳීම් නැත. අඩුම තරමේ අනතුරු ඇඟවීමක්වත් නැත."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"අතුරු බිදුම් නැත"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ප්‍රමුඛ අතුරු බිඳීම් පමණයි"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"ඇඟවීම් පමණි"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"ඔබගේ ඊළඟ සීනුව <xliff:g id="ALARM_TIME">%s</xliff:g> තිබේ"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"ඔබගේ ඊළඟ සීනුව <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> වේ"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> හි තිබෙන ඔබගේ සීනුව ඔබට ඇසෙන්නේ නැත"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"අගුළු ඇරීමට ස්වයිප් කරන්න."</string>
     <string name="phone_hint" msgid="3101468054914424646">"දුරකථන සඳහා දකුණට ස්වයිප් කරන්න"</string>
     <string name="camera_hint" msgid="5241441720959174226">"කැමරාව සඳහා දකුණට ස්වයිප් කරන්න"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"කිසිවක් නැත"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ප්‍රමුඛතාව"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"බාධා කිරීම් නැත"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"ප්‍රමුඛතාව පමණයි"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"ඇඟවීම් පමණි"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"සියලු"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"බාධා\nනොකරන්න"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්‍රමුඛතා\nපමණි"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"පරිශීලක මාරුව"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"පරිශීලකයා මාරු කරන්න,දැන් සිටින පරිශීලකයා <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ප්‍රතික්ෂේප කරන්න"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාරිතා සංවාදයයි"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"මුල් තත්ත්වය නැවත ප්‍රතිසාධනය කිරීමට ස්පර්ශ කරන්න."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"බාධා අවහිර කරන්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index a17b8ec..6ea28f5 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Zapnúť šetrič batérie"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavenia"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Režim v lietadle"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Automatické otočenie obrazovky"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"STLMIŤ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -184,6 +183,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Režim v lietadle je zapnutý."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Stav Nerušiť je zapnutý, iba prioritné."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Stav Nerušiť je zapnutý, žiadne prerušenia."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Stav Nerušiť je zapnutý, iba budíky."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Stav Nerušiť je vypnutý."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Stav Nerušiť je vypnutý."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Stav Nerušiť je zapnutý."</string>
@@ -234,9 +234,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Pult s dezertami"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Šetrič obrazovky"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Režim v lietadle"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Nerušiť"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Iba prioritné"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Iba budíky"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Žiadne prerušenia"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Rozhranie Bluetooth (počet zariadení: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -307,6 +307,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Žiadne vyrušenia, ani budíky"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Žiadne vyrušenia"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Iba prioritné vyrušenia"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Iba budíky"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Ďalší budík: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Ďalší budík: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Váš budík o <xliff:g id="ALARM_TIME">%s</xliff:g> sa nespustí"</string>
@@ -316,9 +317,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Zariadenie odomknete prejdením prstom nahor"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telefón otvoríte prejdením prstom doľava"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Fotoaparát otvoríte prejdením prstom doľava"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Žiadne"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritné"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Žiadne prerušenia"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Iba prioritné"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Iba budíky"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Všetky"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Žiadne\nprerušenia"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Iba\nprioritné"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Iba\nbudíky"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Prepnutie používateľa"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Prepnúť používateľa (súčasný používateľ: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
@@ -376,7 +381,7 @@
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je pripnutá"</string>
     <string name="screen_pinning_description" msgid="1346522416878235405">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Ak ho chcete uvoľniť, stlačte a podržte súčasne tlačidlá Späť a Prehľad."</string>
     <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string>
-    <string name="screen_pinning_positive" msgid="3783985798366751226">"Rozumiem"</string>
+    <string name="screen_pinning_positive" msgid="3783985798366751226">"Dobre"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, vďaka"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Táto položka sa znova zobrazí, keď ju v nastaveniach opätovne zapnete."</string>
@@ -386,4 +391,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odmietnuť"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dialóg hlasitosti"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Klepnutím obnovíte originál."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Blokovanie prerušení"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 177ef1e..3323450 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Vklop varčevanja z energijo"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Nastavitve"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Način za letalo"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Samodejno zasukaj zaslon"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TIHO"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"SAMOD."</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Način za letalo je vklopljen."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Način »ne moti« je vklopljen, samo prednostno."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Način »ne moti« je vklopljen, ni prekinitev."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Način »ne moti« je vklopljen, samo alarmi."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Način »ne moti« je izklopljen."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Način »ne moti« je izklopljen."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Način »ne moti« je vklopljen."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Vitrina za sladice"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Sanjarjenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Način za letalo"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne moti"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prednostno"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Samo alarmi"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Brez prekinitev"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (št. naprav: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Brez motenj. Celo brez alarmov."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Brez prekinitev"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Samo prednostne prekinitve"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Samo alarmi"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Vaš naslednji alarm je ob <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Vaš naslednji alarm: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Alarma ob <xliff:g id="ALARM_TIME">%s</xliff:g> ne boste slišali"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Povlecite, da odklenete"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Povlecite v desno za telefon"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Povlecite v levo za fotoaparat"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Nič"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prednost"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Samo alarmi"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Vse"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Brez\nprekinitev"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprednostno"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Preklop med uporabniki"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Preklop med uporabniki, trenutni uporabnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Zavrni"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je pogovorno okno glede prostornine"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Dotaknite se, če želite obnoviti izvirnik."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 0262dd7..5faa39b 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -45,7 +45,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Укључи штедњу батерије"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Подешавања"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим рада у авиону"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Аутоматско ротирање екрана"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"УГАСИ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АУТОM."</string>
@@ -181,6 +180,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим рада у авиону је укључен."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Подешавање Не узнемиравај је укључено, само приоритетни прекиди."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Подешавање Не узнемиравај је укључено, без прекида."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Подешавање Не узнемиравај је укључено, само аларми."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Подешавање Не узнемиравај је искључено."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Подешавање Не узнемиравај је искључено."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Подешавање Не узнемиравај је укључено."</string>
@@ -231,9 +231,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Витрина са посластицама"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Сањарење"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Етернет"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим рада у авиону"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не узнемиравај"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Само приоритетни прекиди"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Само аларми"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без прекида"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> уређаја)"</string>
@@ -304,6 +304,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Нема прекида. Чак ни аларма."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Без прекида"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Само приоритетни прекиди"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Само аларми"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Следећи аларм је у <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Следећи аларм: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Нећете чути аларм у <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -313,9 +314,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Превуците нагоре да бисте откључали"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Превуците удесно за телефон"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Превуците улево за камеру"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ниједан"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Приоритет"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Само аларми"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Све"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Без\nпрекида"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприорит. прекиди"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Замени корисника"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промените корисника, актуелни корисник је <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -383,4 +390,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Одбиј"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> је дијалог за јачину звука"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Додирните да бисте вратили оригинал."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 71d0596..0659815 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Aktivera batterisparläge"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Inställningar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Flygplansläge"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Rotera skärmen automatiskt"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TYST"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flygplansläget har aktiverats."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Stör ej har aktiverats. Endast prioriterade."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Stör ej har aktiverats. Inga avbrott."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Stör ej är aktiverat, endast alarm."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Stör ej av."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Stör ej har inaktiverats."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Stör ej har aktiverats."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertdisken"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdröm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Flygplansläge"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Stör ej"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Endast prioriterade"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Endast alarm"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Inga avbrott"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> enheter)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Inga avbrott. Inte ens alarm."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Inga avbrott"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Bara prioriterade samtal och aviseringar"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Endast alarm"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Nästa alarm är kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Nästa alarm är <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Alarmet kommer inte att höras kl. <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Dra uppåt om du vill låsa upp"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Dra åt höger om du vill visa telefonen"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Dra åt vänster om du vill visa kameran"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Ingen"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prioritet"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Endast alarm"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Alla"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Stör\nej"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Endast\nprioriterade"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Endast\nalarm"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Byt användare"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Byt användare. Aktuell användare: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Neka"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> används som volymkontroll"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Tryck här om du vill återställa den ursprungliga appen."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1811864..7f3af18 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Washa kiokoa betri"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mipangilio"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Mtandao-Hewa"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Hali ya Ndege"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Skrini ijizungushe kiotomatiki"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"PUUZA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"KIOTOMATIKI"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Hali ya ndegeni imewashwa."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Kipengee cha usinisumbue kimewashwa, kipaumbele pekee."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Kipengee cha usinisumbue kimewashwa, hakuna kukatizwa."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Kipengee cha usinisumbue kimewashwa, kengele pekee."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Kipengee cha usinisumbue kimezimwa."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Kipengee cha usinisumbue kimezimwa."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Kipengee cha usinisumbue kimewashwa."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Sanduku la Vitindamlo"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Hali Tulivu"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Hali ya ndege"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Usinisumbue"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kipaumbele tu"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kengele pekee"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Hakuna kukatizwa"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (Vifaa <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Hakuna kukatizwa. Hata kama ni kengele."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Hakuna kukatizwa"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Mambo yenye kipaumbele pekee yakatize"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Kengele pekee"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Kengele yako inayofuata itakuwa saa <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Kengele yako inayofuata itakuwa <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Hutasikia kengele yako ifikapo <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Telezesha kidole ili ufungue"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telezesha kidole kulia ili ufikie simu"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Telezesha kidole kushoto ili ufikie kamera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Hamna"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Kipaumbele"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Hakuna kukatizwa"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Kipaumbele tu"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Kengele pekee"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Zote"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Hakuna\nukatizaji"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kipaumbele\npekee"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kengele\npekee"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Badili mtumiaji"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Badili mtumiaji, mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Kataa"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ni mazungumzo ya sauti"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Gusa ili urejeshe ya awali."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Zuia ukatizaji"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 156fa65..4d7d6b5 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -19,12 +19,6 @@
         <item name="android:layout_width">480dp</item>
     </style>
 
-    <style name="SearchPanelScrim">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">@dimen/search_panel_scrim_height</item>
-        <item name="android:layout_gravity">bottom</item>
-    </style>
-
     <style name="UserDetailView">
         <item name="numColumns">4</item>
     </style>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 1c246c5..17626cc 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"பேட்டரி சேமிப்பானை இயக்கு"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"அமைப்பு"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"வைஃபை"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"விமானப் பயன்முறை"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"திரையைத் தானாகச் சுழற்று"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"முடக்கு"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"தானியங்கு"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"விமானப் பயன்முறை இயக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது, முதன்மை மட்டும்."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது, குறுக்கீடுகள் இல்லை."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது, அலாரங்கள் மட்டும்."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"தொந்தரவு செய்ய வேண்டாம் என்பது முடக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"தொந்தரவு செய்ய வேண்டாம் என்பது முடக்கப்பட்டது."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"தொந்தரவு செய்ய வேண்டாம் என்பது இயக்கப்பட்டது."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"இனிப்பு வடிவங்கள்"</string>
     <string name="start_dreams" msgid="7219575858348719790">"பகல்கனா"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ஈதர்நெட்"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"விமானப் பயன்முறை"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"தொந்தரவு செய்ய வேண்டாம்"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"முதன்மை மட்டும்"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"அலாரங்கள் மட்டும்"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"குறுக்கீடுகள் வேண்டாம்"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"புளூடூத்"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"புளூடூத் (<xliff:g id="NUMBER">%d</xliff:g> சாதனங்கள்)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"அறிவிப்பும் இல்லை. அலாரங்களும் இல்லை."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"தெரிவிக்காதே"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"முக்கிய அறிவிப்புகள் மட்டும்"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"அலாரங்கள் மட்டும்"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"அடுத்த அலாரம் - <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"அடுத்த அலாரம் - <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> க்கு அலாரத்தைக் கேட்க மாட்டீர்கள்"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"திறக்க, மேலே ஸ்வைப் செய்யவும்"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ஃபோனுக்கு, வலப்புறம் ஸ்வைப் செய்க"</string>
     <string name="camera_hint" msgid="5241441720959174226">"கேமராவிற்கு இடப்புறம் ஸ்வைப் செய்க"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ஏதுமில்லை"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"முன்னுரிமை"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"குறுக்கீடுகள் வேண்டாம்"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"முதன்மை மட்டும்"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"அலாரங்கள் மட்டும்"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"எல்லாம்"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"குறுக்கீடுகள்\nஇல்லை"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"முதன்மை\nமட்டும்"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"அலாரங்கள்\nமட்டும்"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"பயனரை மாற்று"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"பயனரை மாற்று, தற்போதைய பயனர் <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"நிராகரி"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"ஒலியளவு செய்தி: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"அசலை மீட்டமைக்கத் தொடவும்."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"குறுக்கீடுகளைத் தடுக்கவும்"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index cc5d2ad..f8cc692 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"బ్యాటరీ సేవర్‌ను ఆన్ చేయి"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"సెట్టింగ్‌లు"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ఎయిర్‌ప్లేన్ మోడ్"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"స్క్రీన్‌ను స్వయంచాలకంగా తిప్పండి"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"మ్యూట్"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"స్వయంచాలకం"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ఎయిర్‌ప్లైన్ మోడ్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"అంతరాయం కలిగించవద్దు ఆన్‌లో ఉంది, ప్రాధాన్యత మాత్రమే."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"అంతరాయం కలిగించవద్దు ఆన్‌లో ఉంది, అంతరాయాలు ఉండవు."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"అంతరాయం కలిగించవద్దు ఆన్‌లో ఉంది, అలారాలు మాత్రమే."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"అంతరాయం కలిగించవద్దు ఆఫ్‌లో ఉంది."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"అంతరాయం కలిగించవద్దు ఆఫ్ చేయబడింది."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"అంతరాయం కలిగించవద్దు ఆన్ చేయబడింది."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"డెజర్ట్ కేస్"</string>
     <string name="start_dreams" msgid="7219575858348719790">"డేడ్రీమ్"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ఈథర్‌నెట్"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ఎయిర్‌ప్లేన్ మోడ్"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"అంతరాయం కలిగించవద్దు"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"ప్రాధాన్యత మాత్రమే"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"అలారాలు మాత్రమే"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"అంతరాయాలు ఉండవు"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"బ్లూటూత్"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"బ్లూటూత్ (<xliff:g id="NUMBER">%d</xliff:g> పరికరాలు)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"అంతరాయాలు లేవు. అలారాలు కూడా లేవు."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"అంతరాయాలు లేకుండా"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"ప్రాధాన్య అంతరాయాలు మాత్రమే"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"అలారాలు మాత్రమే"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"మీ తదుపరి అలారం <xliff:g id="ALARM_TIME">%s</xliff:g>కి ఉంది"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"మీ తదుపరి అలారం <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"మీరు <xliff:g id="ALARM_TIME">%s</xliff:g>కి సెట్ చేసిన అలారం మీకు వినిపించదు"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"అన్‌లాక్ చేయడానికి ఎగువకు స్వైప్ చేయండి"</string>
     <string name="phone_hint" msgid="3101468054914424646">"ఫోన్ కోసం కుడివైపుకి స్వైప్ చేయండి"</string>
     <string name="camera_hint" msgid="5241441720959174226">"కెమెరా కోసం ఎడమవైపుకి స్వైప్ చేయండి"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"వేటికీ వద్దు"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ప్రాధాన్యత"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"అంతరాయాలు ఉండవు"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"ప్రాధాన్యత మాత్రమే"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"అలారాలు మాత్రమే"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"అన్నిటికీ"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"అంతరాయాలు\nఉండకూడదు"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ప్రాధాన్యమైనవి\nమాత్రమే"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"అలారాలు\nమాత్రమే"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"వినియోగదారుని మార్చు"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"వినియోగదారుని మార్చు, ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"తిరస్కరించు"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> అనేది వాల్యూమ్ డైలాగ్"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"అసలుదాన్ని పునరుద్ధరించడానికి తాకండి."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"అంతరాయాలను బ్లాక్ చేయండి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 1c064e5..978ff25 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"เปิดโหมดประหยัดแบตเตอรี่"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"การตั้งค่า"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WiFi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"โหมดใช้งานบนเครื่องบิน"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"หมุนหน้าจออัตโนมัติ"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ปิดเสียง"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"อัตโนมัติ"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"เปิดโหมดบนเครื่องบินแล้ว"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"การห้ามรบกวนเปิดอยู่ เฉพาะเรื่องสำคัญเท่านั้น"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"การห้ามรบกวนเปิดอยู่ ห้ามรบกวน"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"เปิดการห้ามรบกวนอยู่ ปลุกได้เท่านั้น"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"การห้ามรบกวนปิดอยู่"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ปิดการห้ามรบกวนแล้ว"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"เปิดการห้ามรบกวนแล้ว"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ชั้นแสดงของหวาน"</string>
     <string name="start_dreams" msgid="7219575858348719790">"เดย์ดรีม"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"อีเทอร์เน็ต"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"โหมดใช้บนเครื่องบิน"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ห้ามรบกวน"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"เฉพาะเรื่องสำคัญ"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"เฉพาะปลุกเท่านั้น"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"ไม่มีการรบกวน"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"บลูทูธ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"บลูทูธ (<xliff:g id="NUMBER">%d</xliff:g> อุปกรณ์)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"ไม่มีการรบกวน แม้แต่นาฬิกาปลุก"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"ไม่มีการรบกวน"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"เฉพาะเรื่องสำคัญเท่านั้น"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"เฉพาะปลุกเท่านั้น"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"การปลุกครั้งถัดไปของคุณคือเวลา <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"การปลุกครั้งถัดไปของคุณคือ <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"คุณจะไม่ได้ยินเสียงปลุกในเวลา <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"กวาดขึ้นเพื่อปลดล็อก"</string>
     <string name="phone_hint" msgid="3101468054914424646">"กวาดไปทางขวาเพื่อใช้โทรศัพท์"</string>
     <string name="camera_hint" msgid="5241441720959174226">"กวาดไปทางซ้ายเพื่อใช้กล้องถ่ายรูป"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"ไม่มี"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"สำคัญ"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"เฉพาะปลุกเท่านั้น"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"ทั้งหมด"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"ไม่มี\nการรบกวน"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"เฉพาะเรื่อง\nสำคัญ"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"เฉพาะปลุก\nเท่านั้น"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"สลับผู้ใช้"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"เปลี่ยนผู้ใช้จากผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ปฏิเสธ"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> เป็นช่องโต้ตอบระดับเสียง"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"แตะเพื่อคืนค่าดั้งเดิม"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 6ecd402..19cb066 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"I-on ang pagtitipid ng baterya"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Mga Setting"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Airplane mode"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"I-auto-rotate ang screen"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Na-on ang Airplane mode."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Naka-on ang huwag istorbohin, priyoridad lang."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Naka-on ang huwag istorbohin, walang mga paggambala."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Naka-on ang huwag istorbohin, mga alarm lang."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Naka-off ang huwag istorbohin."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Na-off na ang huwag istorbohin"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Na-on na ang huwag istorbohin."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Airplane mode"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Huwag istorbohin"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Priyoridad lang"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Mga alarm lang"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Walang mga paggambala"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> (na) Device)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Walang mga pagkaantala. Kahit mga alarma."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Walang mga paggambala"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Mga may priyoridad na paggambala lang"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Mga alarm lang"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Ang susunod mong alarma ay sa <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Ang susunod mong alarma ay <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Hindi mo maririnig ang alarma mo ng <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Mag-swipe pataas upang i-unlock"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Mag-swipe pakanan para sa telepono"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Mag-swipe pakaliwa para sa camera"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Wala"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Prayoridad"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Walang pagkaantala"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Priyoridad lang"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Mga alarm lang"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Lahat"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Walang\npagkaantala"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priyoridad\nlang"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Mga alarm\nlang"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Magpalit ng user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Magpalit ng user, kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Tanggihan"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ang volume dialog"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Pindutin upang ibalik ang orihinal."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"I-block ang mga pagkaantala"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 7209af0..bfbdcb7 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Pil tasarrufunu aç"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Ayarlar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Kablosuz"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Uçak modu"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekranı otomatik döndür"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"KAPAT"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"OTOMTK"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Uçak modu açıldı."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Rahatsız etmeyin ayarı açık, yalnızca öncelikliler."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Rahatsız etmeyin ayarı açık, kesme yok."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Rahatsız etmeyin ayarı açık, yalnızca alarmlar."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Rahatsız etmeyin\" ayarı kapalı."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Rahatsız etmeyin\" ayarı kapalı."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Rahatsız etmeyin\" ayarı açık."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Tatlı Kutusu"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Hafif uyku"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Uçak modu"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Rahatsız etmeyin"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Yalnızca öncelikliler"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Yalnızca alarmlar"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Kesme yok"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> Cihaz)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Kesinti yok. Uyarı bile yok."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Kesinti yok"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Sadece öncelikli kesintiler"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Yalnızca alarmlar"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Bir sonraki alarmın saati: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Bir sonraki alarmınız: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"<xliff:g id="ALARM_TIME">%s</xliff:g> olarak ayarlanan alarmı duymayacaksınız"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Kilidi açmak için hızlıca yukarı kaydırın"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telefon için sağa kaydırın"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Kamera için sola kaydırın"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Yok"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Öncelik"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Yalnızca alarmlar"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tümü"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Kesinti\nyok"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnızca\nöncelik"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnızca\nalarmlar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kullanıcı değiştirme"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kullanıcı değiştir. Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Reddet"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olarak ayarlandı"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Orijinali geri yüklemek için dokunun."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8c582f8..8855193 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -46,7 +46,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Увімкнути режим заощадження заряду акумулятора"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Налаштування"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Режим польоту"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Повертати екран автоматично"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ІГНОР."</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТОМ."</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Режим польоту ввімкнено."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Режим \"Не турбувати\" ввімкнено, лише пріоритетні."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Режим \"Не турбувати\" ввімкнено, без сповіщень."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Увімкнено режим \"Не турбувати\", дозволено лише сигнали."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Режим \"Не турбувати\" вимкнено."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Режим \"Не турбувати\" вимкнено."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Режим \"Не турбувати\" ввімкнено."</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Вітрина десертів"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Заставка"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Режим польоту"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не турбувати"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Лише пріоритетні"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Лише сигнали"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Без сповіщень"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (пристроїв: <xliff:g id="NUMBER">%d</xliff:g>)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Без сповіщень і сигналів будильника."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Без сповіщень"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Лише пріоритетні сповіщення"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Лише сигнали"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Наступний сигнал: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Наступний сигнал: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Сигнал не лунатиме о <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -314,9 +315,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Проведіть пальцем угору, щоб розблокувати"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Проведіть пальцем праворуч, щоб скористатися телефоном"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Проведіть пальцем ліворуч, щоб скористатися камерою"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Немає"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Пріоритетні"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Без сповіщень"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Лише пріоритетні"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Лише сигнали"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Усі"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Без\nсповіщень"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Лише\nприорітетні"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Лише\nсигнали"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Змінити користувача"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Змінити користувача, поточний користувач – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +389,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Відхилити"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> призначено регулятором гучності"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Торкніться, щоб відновити оригінал."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Блокувати сповіщення"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index f402071..89ccfa3 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"بیٹری کی بچت آن کریں"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"ترتیبات"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"ہوائی جہاز وضع"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"سکرین کو خودکار طور پر گھمائیں"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"خاموش کریں"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"خودکار"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"ہوائی جہاز وضع کو آن کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"ڈسٹرب نہ کریں آن ہے، صرف ترجیحی۔"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"ڈسٹرب نہ کریں آن ہے، کوئی مداخلتیں نہیں۔"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"ڈسٹرب نہ کریں آن ہے، صرف الارمز۔"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"ڈسٹرب نہ کریں آف ہے۔"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"ڈسٹرب نہ کریں کو آف کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"ڈسٹرب نہ کریں کو آن کر دیا گیا۔"</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"ڈیزرٹ کیس"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"ایتھرنیٹ"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"ہوائی جہاز طرز"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"ڈسٹرب نہ کریں"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"صرف ترجیحی"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"صرف الارمز"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"کوئی مداخلتیں نہیں"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوٹوتھ"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوٹوتھ (<xliff:g id="NUMBER">%d</xliff:g> آلات)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"کوئی مداخلتیں نہیں ہیں۔ یہاں تک کہ الارمز بھی نہیں ہیں۔"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"کوئی مداخلتیں نہیں ہیں"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"صرف ترجیحی مداخلتیں"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"صرف الارمز"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"آپ کا اگلا الارم <xliff:g id="ALARM_TIME">%s</xliff:g> بجے ہے"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"آپ کا اگلا الارم <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g> ہے"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"آپ کو <xliff:g id="ALARM_TIME">%s</xliff:g> بجے اپنا الارم سنائی نہیں دیگا"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"غیر مقفل کرنے کیلئے اوپر سوائپ کریں"</string>
     <string name="phone_hint" msgid="3101468054914424646">"فون کیلئے دائیں سوائپ کریں"</string>
     <string name="camera_hint" msgid="5241441720959174226">"کیمرہ کیلئے بائیں سوائپ کریں"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"کوئی نہیں"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"ترجیح"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"صرف الارمز"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"سبھی"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"کوئی مداخلتیں\nنہیں"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"صرف\nترجیحی"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"صرف\nالارمز"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"صارف سوئچ کریں"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"صارف سوئچ کریں، موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"مسترد کریں"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ ہے"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"اصل کو بحال کرنے کیلئے ٹچ کریں۔"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 782d5e1..156aeb6 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Quvvat tejash funksiyasini yoqing"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Sozlamalar"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Parvoz rejimi"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ekranni avtomatik burish"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"MUTE"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"AUTO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Parvoz rejimi yoqildi."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"“Bezovta qilinmasin” funksiyasi yoqilgan, faqat muhim bildirishnomalar ko‘rsatiladi."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"“Bezovta qilinmasin” funksiyasi yoqilgan, bezovta qilinmaydi."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Bezovta qilinmasin, faqat signallar"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"“Bezovta qilinmasin” funksiyasi o‘chirilgan."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"“Bezovta qilinmasin” funksiyasi o‘chirildi."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"“Bezovta qilinmasin” funksiyasi yoqildi."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Tush kurish"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Parvoz rejimi"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Bezovta qilinmasin"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Faqat muhimlari"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Faqat signallar"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Tanaffuslarsiz"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g>ta qurilma)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Hech narsa bezovta qilmaydi, hatto uyg‘otkichlar ham."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Tanaffuslarsiz"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Faqat ustuvor tanaffuslar"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Faqat signallar"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Keyingi uyg‘otkich: <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Keyingi uyg‘otkich: <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Keyingi uyg‘otkich: <xliff:g id="ALARM_TIME">%s</xliff:g>. Ovoz eshitilmaydi."</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Qulfdan chiqarish uchun yuqoriga suring"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Telefonni ochish uchun o‘ngga"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Kamerani ochish uchun chapga suring"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Hech biri"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Ustuvorlik"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Bezovta qilinishlarsiz"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Faqat muhimlari"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Faqat signallar"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Barchasi"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Uzilishlar\nbo‘lmasin"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Faqat\nmuhimlar"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Faqat\nsignallar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Foydalanuvchini almashtirish"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Foydalanuvchini o‘zgartirish. Joriy foydalanuvchi – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rad etish"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ovoz balandligini boshqaradi"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Aslini tiklash uchun bosing."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Bezovta qilinishlar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 7343c6f..f7885d7 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Bật trình tiết kiệm pin"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Cài đặt"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Chế độ trên máy bay"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Tự động xoay màn hình"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"TẮT TIẾNG"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"TỰ ĐỘNG"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Đã bật chế độ trên máy bay."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Bật tính năng không làm phiền, chỉ ưu tiên."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Bật tính năng không làm phiền, không có gián đoạn."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Bật tính năng không làm phiền, chỉ báo thức."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Tắt tính năng không làm phiền."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Đã tắt tính năng không làm phiền."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Đã bật tính năng không làm phiền."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Tủ trưng bày bánh ngọt"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Chế độ ngủ"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Chế độ trên máy bay"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Không làm phiền"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Chỉ ưu tiên"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Chỉ báo thức"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Không có gián đoạn nào"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> thiết bị)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Không có gián đoạn. Thậm chí không có cảnh báo."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Không có gián đoạn nào"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Chỉ các gián đoạn ưu tiên"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Chỉ báo thức"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"Lần báo thức tiếp theo của bạn vào lúc <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"Lần báo thức tiếp theo của bạn là <xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Bạn sẽ không nghe thấy báo thức lúc <xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Vuốt lên để mở khóa"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Vuốt sang phải để mở điện thoại"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Vuốt sang trái để mở máy ảnh"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Không có"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Ưu tiên"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Chỉ báo thức"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Tất cả"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Không có\ngián đoạn"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Chỉ\nưu tiên"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Chỉ\nbáo thức"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Chuyển đổi người dùng"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Chuyển người dùng, người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +389,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Từ chối"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> là hộp thoại khối lượng"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Chạm để khôi phục bản gốc."</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index ca2cfef..52f4ed0 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"开启节电助手"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"设置"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"WLAN"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飞行模式"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自动旋转屏幕"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"静音"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"自动"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飞行模式已开启。"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"勿扰模式已开启,仅限优先打扰。"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"勿扰模式已开启,禁止打扰。"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"勿扰模式已开启,仅限闹钟。"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"勿扰模式关闭。"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"已关闭勿扰模式。"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"已开启勿扰模式。"</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"甜品盒"</string>
     <string name="start_dreams" msgid="7219575858348719790">"互动屏保"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"有线网络"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飞行模式"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"勿扰"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"仅限优先打扰"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"仅限闹钟"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"禁止打扰"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"蓝牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"蓝牙(<xliff:g id="NUMBER">%d</xliff:g> 台设备)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"零打扰(甚至不发出闹钟提醒)。"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"禁止打扰"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"仅限优先打扰内容"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"仅限闹钟"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"下次闹钟响铃时间:<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"下次闹钟响铃时间:<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"您在<xliff:g id="ALARM_TIME">%s</xliff:g>将不会听到闹钟响铃"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑动即可解锁"</string>
     <string name="phone_hint" msgid="3101468054914424646">"向右滑动可打开拨号界面"</string>
     <string name="camera_hint" msgid="5241441720959174226">"向左滑动可打开相机"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"无"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"优先"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"仅限闹钟"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"禁止\n打扰"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"仅限\n优先打扰"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"仅限\n闹钟"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切换用户"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切换用户,当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒绝"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已用作音量控制对话框"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"触摸即可恢复原始设置。"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 04a841d..f5b3e1d 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"開啟省電模式"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動旋轉螢幕"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"關閉"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"自動"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飛行模式已開啟。"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"開啟「請勿騷擾」,僅限優先。"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"開啟「請勿騷擾」,不允許干擾。"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"開啟「請勿騷擾」,僅限鬧鐘。"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"「請勿騷擾」關閉"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"已關閉「請勿騷擾」。"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"已開啟「請勿騷擾」。"</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Daydream"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"以太網"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛行模式"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"請勿騷擾"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"僅限優先"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"僅限鬧鐘"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"不允許干擾"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 部裝置)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"不干擾 (即使鬧鐘也不例外)。"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"不允許干擾"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"只限重要干擾"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"僅限鬧鐘"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"下次鬧鐘時間:<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"下次鬧鐘時間:<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"您不會聽到<xliff:g id="ALARM_TIME">%s</xliff:g> 的鬧鐘"</string>
@@ -314,9 +315,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上快速滑動即可解鎖"</string>
     <string name="phone_hint" msgid="3101468054914424646">"向右快速滑動即可使用手機功能"</string>
     <string name="camera_hint" msgid="5241441720959174226">"向左快速滑動即可使用相機功能"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"無"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"重要"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"不允許干擾"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"僅限優先"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"僅限鬧鐘"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"不允許\n干擾"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅限\n優先"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅限\n鬧鐘"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +389,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話框"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸即可復原。"</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"封鎖干擾"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 98ae37c..77156c0 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"開啟節約耗電量模式"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"設定"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"飛行模式"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"自動旋轉螢幕"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"關閉"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"自動"</string>
@@ -182,6 +181,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"飛航模式已開啟。"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"「零打擾」設定為開啟,只會顯示優先通知。"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"「零打擾」設定為開啟,不接受任何干擾。"</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"「零打擾」設定為開啟,只會顯示鬧鐘。"</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"「零打擾」設定為關閉。"</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"已停用「零打擾」設定。"</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"已啟用「零打擾」設定。"</string>
@@ -232,9 +232,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessert Case"</string>
     <string name="start_dreams" msgid="7219575858348719790">"休眠模式"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"乙太網路"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"飛航模式"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"零打擾"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"僅顯示優先通知"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"僅允許鬧鐘"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"無干擾"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"藍牙"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"藍牙 (<xliff:g id="NUMBER">%d</xliff:g> 個裝置)"</string>
@@ -305,6 +305,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"不干擾 (即使鬧鐘也不例外)。"</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"不允許干擾"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"僅限優先干擾"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"僅允許鬧鐘"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"下次鬧鐘時間:<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"下次鬧鐘時間:<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"您不會聽到<xliff:g id="ALARM_TIME">%s</xliff:g> 的鬧鐘"</string>
@@ -314,9 +315,15 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"向上滑動即可解鎖"</string>
     <string name="phone_hint" msgid="3101468054914424646">"向右滑動可使用手機功能"</string>
     <string name="camera_hint" msgid="5241441720959174226">"向左滑動可使用相機功能"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"無"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"優先"</string>
+    <!-- no translation found for interruption_level_none (8284541443482072628) -->
+    <skip />
+    <!-- no translation found for interruption_level_priority (6426766465363855505) -->
+    <skip />
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"僅允許鬧鐘"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"全部"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"無\n干擾"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅允許\n優先通知"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅允許\n鬧鐘"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -384,4 +391,6 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在是預設的音量控制對話方塊。"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸這裡即可恢復原始設定。"</string>
+    <!-- no translation found for volume_zen_switch_text (6388350641576595452) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 0136eb1..6910873 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -44,7 +44,6 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Vula isilondolozi sebhethri"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Izilungiselelo"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"I-Wi-Fi"</string>
-    <string name="status_bar_settings_airplane" msgid="4879879698500955300">"Imodi yendiza"</string>
     <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Ukuzulazula kweskrini okuzenzakalelayo"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"THULISA"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"OKUZENZAKALELAYO"</string>
@@ -180,6 +179,7 @@
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Imodi yendiza ivuliwe."</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Ukungaphazamisi kuvuliwe, okubalulekile kuphela."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"Ungaphazamisi, akukho ukuphazamiseka."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Ukungaphazamisi kuvuliwe, ama-alamu kuphela."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Ukungaphazamisi kuvaliwe."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Ukungaphazamisi kuvaliwe."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Ukungaphazamisi kuvuliwe."</string>
@@ -230,9 +230,9 @@
     <string name="dessert_case" msgid="1295161776223959221">"Isikhwama soswidi"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Ukuphupha emini"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"I-Ethernet"</string>
-    <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"Isimo sendiza"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ungaphazamisi"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Okubalulekile kuphela"</string>
+    <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Ama-alamu kuphela"</string>
     <string name="quick_settings_dnd_none_label" msgid="7309935569360609114">"Azikho iziphazamiso"</string>
     <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"I-Bluetooth"</string>
     <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"I-Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> amadivayisi)"</string>
@@ -303,6 +303,7 @@
     <string name="zen_no_interruptions_with_warning" msgid="4396898053735625287">"Akukho ukuphazamiseka. Nama-alamu imbala."</string>
     <string name="zen_no_interruptions" msgid="7970973750143632592">"Azikho iziphazamiso"</string>
     <string name="zen_important_interruptions" msgid="3477041776609757628">"Iziphazamiso ezibalulekile kuphela"</string>
+    <string name="zen_alarms" msgid="5055668280767657759">"Ama-alamu kuphela"</string>
     <string name="zen_alarm_information_time" msgid="5235772206174372272">"I-alamu yakho elandelayo ingo<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_information_day_time" msgid="8422733576255047893">"I-alamu yakho elandelayo ingo-<xliff:g id="ALARM_DAY_AND_TIME">%s</xliff:g>"</string>
     <string name="zen_alarm_warning" msgid="6873910860111498041">"Ngeke uzwe i-alamu yakho ngo-<xliff:g id="ALARM_TIME">%s</xliff:g>"</string>
@@ -312,9 +313,13 @@
     <string name="keyguard_unlock" msgid="8043466894212841998">"Swayiphela phezulu ukuze uvule"</string>
     <string name="phone_hint" msgid="3101468054914424646">"Swayiphela ngakwesokudla ukuze uthole ifoni"</string>
     <string name="camera_hint" msgid="5241441720959174226">"Swayiphela ngakwesokunxele ukuze uthole ikhamela"</string>
-    <string name="interruption_level_none" msgid="3831278883136066646">"Lutho"</string>
-    <string name="interruption_level_priority" msgid="6517366750688942030">"Okubalulekile"</string>
+    <string name="interruption_level_none" msgid="8284541443482072628">"Azikho iziphazamiso"</string>
+    <string name="interruption_level_priority" msgid="6426766465363855505">"Okubalulekile kuphela"</string>
+    <string name="interruption_level_alarms" msgid="5226306993448328896">"Ama-alamu kuphela"</string>
     <string name="interruption_level_all" msgid="1330581184930945764">"Konke"</string>
+    <string name="interruption_level_none_twoline" msgid="3942121050170227056">"Akukho\nukuphazamiseka"</string>
+    <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Okubalulekile\nkuphela"</string>
+    <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ama-alamu\nkuphela"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Shintsha umsebenzisi"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Shintsha umsebenzisi, umsebenzisi wamanje ngu-<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -382,4 +387,5 @@
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Phika"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> yingxoxo yevolumu"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Thinta ukuze ubuyisele kokwangempela."</string>
+    <string name="volume_zen_switch_text" msgid="6388350641576595452">"Vimba iziphazamiso"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 6ecdca3..24f92ef 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -72,5 +72,15 @@
         <attr name="verticalSpacing" format="dimension" />
         <attr name="horizontalSpacing" format="dimension" />
     </declare-styleable>
+
+    <!-- Theme for icons in the status bar (light/dark). background/fillColor is used for dual tone
+         icons like wifi and signal, and singleToneColor is used for icons with only one tone.
+         Contract: Pixel with fillColor blended over backgroundColor blended over translucent should
+         equal to singleToneColor blended over translucent. -->
+    <declare-styleable name="TonedIcon">
+        <attr name="backgroundColor" format="integer" />
+        <attr name="fillColor" format="integer" />
+        <attr name="singleToneColor" format="integer" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d4aeab6..ded7c4e 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -108,8 +108,7 @@
     <color name="notification_guts_text_color">#b2FFFFFF</color>
     <color name="notification_guts_btn_color">#FFFFFFFF</color>
 
-    <color name="search_panel_circle_color">#ffffff</color>
-    <color name="search_panel_ripple_color">#ffbbbbbb</color>
+    <color name="assist_orb_color">#ffffff</color>
 
     <color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
     <color name="doze_small_icon_background_color">#ff434343</color>
@@ -130,5 +129,12 @@
     <color name="segmented_button_selected">#FFFFFFFF</color>
     <color name="segmented_button_unselected">#B3B0BEC5</color><!-- 70% blue grey 200 -->
     <color name="volume_panel_divider">#1FFFFFFF</color><!-- 12% white -->
-    <color name="light_mode_icon_color">#FF616161</color><!-- grey 700 -->
+
+    <color name="dark_mode_icon_color_single_tone">#99000000</color>
+    <color name="dark_mode_icon_color_dual_tone_background">#3d000000</color>
+    <color name="dark_mode_icon_color_dual_tone_fill">#7a000000</color>
+
+    <color name="light_mode_icon_color_single_tone">#ffffff</color>
+    <color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
+    <color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c24cd64..b6ff1ce 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -471,22 +471,23 @@
     <dimen name="go_to_full_shade_appearing_translation">200dp</dimen>
 
     <!-- The diameter of the search panel circle. -->
-    <dimen name="search_panel_circle_size">88dp</dimen>
+    <dimen name="assist_orb_size">144dp</dimen>
 
-    <!-- The margin to the edge of the screen from where the circle starts to appear -->
-    <dimen name="search_panel_circle_base_margin">80dp</dimen>
+    <!-- The margin to the edge of the screen from where the orb starts to appear -->
+    <dimen name="assist_orb_base_margin">22dp</dimen>
 
-    <!-- The amount the circle translates when appearing -->
-    <dimen name="search_panel_circle_travel_distance">80dp</dimen>
+    <!-- The amount the orb translates when appearing -->
+    <dimen name="assist_orb_travel_distance">26dp</dimen>
 
-    <!-- The elevation of the search panel circle -->
-    <dimen name="search_panel_circle_elevation">12dp</dimen>
+    <!-- The elevation of the orb -->
+    <dimen name="assist_orb_elevation">12dp</dimen>
 
-    <!-- The height of the scrim behind the search panel circle. -->
-    <dimen name="search_panel_scrim_height">250dp</dimen>
+    <!-- The height of the scrim behind the orb. -->
+    <dimen name="assist_orb_scrim_height">250dp</dimen>
 
-    <!-- How far the user needs to drag up to invoke search. -->
-    <dimen name="search_panel_threshold">100dp</dimen>
+    <!-- The height of the scrim behind the search panel circle. Should be navigation_bar_height
+         + 8dp. -->
+    <dimen name="assist_orb_navbar_scrim_height">56dp</dimen>
 
     <!-- The width/height of the phone/camera/unlock icon view on keyguard. -->
     <dimen name="keyguard_affordance_height">56dp</dimen>
@@ -572,4 +573,7 @@
     <!-- Screen pinning inner nav bar outer circle size -->
     <dimen name="screen_pinning_nav_highlight_outer_size">84dp</dimen>
 
+    <!-- Padding to be used on the bottom of the fingerprint icon on Keyguard so it better aligns
+         with the other icons. -->
+    <dimen name="fingerprint_icon_additional_padding">12dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index b696787..779b55e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -100,9 +100,6 @@
     <!-- Name of the button that links to the Wifi settings screen. [CHAR LIMIT=NONE] -->
     <string name="status_bar_settings_wifi_button">Wi-Fi</string>
 
-    <!-- Label in the system panel for airplane mode (all radios are turned off)[CHAR LIMIT=30] -->
-    <string name="status_bar_settings_airplane">Airplane mode</string>
-
     <!-- Label in system panel saying the device will use the orientation sensor to rotate [CHAR LIMIT=30] -->
     <string name="status_bar_settings_auto_rotation">Auto-rotate screen</string>
 
@@ -438,6 +435,8 @@
     <string name="accessibility_quick_settings_dnd_priority_on">Do not disturb on, priority only.</string>
     <!-- Content description of the do not disturb tile in quick settings when on in none (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, no interruptions.</string>
+    <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd_alarms_on">Do not disturb on, alarms only.</string>
      <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
     <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -566,12 +565,12 @@
     <!-- Textual description of Ethernet connections -->
     <string name="ethernet_label">Ethernet</string>
 
-    <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_airplane_mode_label">Airplane mode</string>
     <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_label">Do not disturb</string>
     <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_priority_label">Priority only</string>
+    <!-- QuickSettings: Do not disturb - Alarms only [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_dnd_alarms_label">Alarms only</string>
     <!-- QuickSettings: Do not disturb - No interruptions [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_none_label">No interruptions</string>
     <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] -->
@@ -730,6 +729,9 @@
     <!-- Zen mode: Only important interruptions. [CHAR LIMIT=40] -->
     <string name="zen_important_interruptions">Priority interruptions only</string>
 
+    <!-- Zen mode: Only alarms. [CHAR LIMIT=40] -->
+    <string name="zen_alarms">Alarms only</string>
+
     <!-- Zen mode: Next alarm information - just a time. [CHAR LIMIT=40] -->
     <string name="zen_alarm_information_time">Your next alarm is at <xliff:g id="alarm_time" example="5:00 PM">%s</xliff:g></string>
 
@@ -758,14 +760,26 @@
     <string name="camera_hint">Swipe left for camera</string>
 
     <!-- Interruption level: None. [CHAR LIMIT=20] -->
-    <string name="interruption_level_none">None</string>
+    <string name="interruption_level_none">No interruptions</string>
 
     <!-- Interruption level: Priority. [CHAR LIMIT=20] -->
-    <string name="interruption_level_priority">Priority</string>
+    <string name="interruption_level_priority">Priority only</string>
+
+    <!-- Interruption level: Alarms only. [CHAR LIMIT=20] -->
+    <string name="interruption_level_alarms">Alarms only</string>
 
     <!-- Interruption level: All. [CHAR LIMIT=20] -->
     <string name="interruption_level_all">All</string>
 
+    <!-- Interruption level: None.  Optimized for narrow two-line display. [CHAR LIMIT=20] -->
+    <string name="interruption_level_none_twoline">No\ninterruptions</string>
+
+    <!-- Interruption level: Priority.  Optimized for narrow two-line display. [CHAR LIMIT=20] -->
+    <string name="interruption_level_priority_twoline">Priority\nonly</string>
+
+    <!-- Interruption level: Alarms only.  Optimized for narrow two-line display. [CHAR LIMIT=20] -->
+    <string name="interruption_level_alarms_twoline">Alarms\nonly</string>
+
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
     <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
 
@@ -965,4 +979,7 @@
 
     <!-- VolumeUI restoration notification: text -->
     <string name="volumeui_notification_text">Touch to restore the original.</string>
+
+    <!-- Volume dialog zen toggle switch title -->
+    <string name="volume_zen_switch_text">@*android:string/zen_mode_feature_name</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 07fcb82..107a8ec 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -246,12 +246,6 @@
         <item name="android:layout_height">match_parent</item>
     </style>
 
-    <style name="SearchPanelScrim">
-        <item name="android:layout_width">match_parent</item>
-        <item name="android:layout_height">@dimen/search_panel_scrim_height</item>
-        <item name="android:layout_gravity">bottom</item>
-    </style>
-
     <style name="UserDetailView">
         <item name="numColumns">3</item>
     </style>
@@ -265,4 +259,15 @@
         <item name="android:backgroundDimEnabled">false</item>
         <item name="android:alertDialogTheme">@style/Theme.SystemUI.Dialog.Alert</item>
     </style>
+
+    <style name="DualToneLightTheme">
+        <item name="backgroundColor">@color/light_mode_icon_color_dual_tone_background</item>
+        <item name="fillColor">@color/light_mode_icon_color_dual_tone_fill</item>
+        <item name="singleToneColor">@color/light_mode_icon_color_single_tone</item>
+    </style>
+    <style name="DualToneDarkTheme">
+        <item name="backgroundColor">@color/dark_mode_icon_color_dual_tone_background</item>
+        <item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
+        <item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/values/volume.xml b/packages/SystemUI/res/values/volume.xml
new file mode 100644
index 0000000..f516104
--- /dev/null
+++ b/packages/SystemUI/res/values/volume.xml
@@ -0,0 +1,87 @@
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item name="volume_expand_animation_duration" type="integer">300</item>
+
+    <color name="volume_icon_color">#ffffffff</color>
+    <color name="volume_settings_icon_color">#7fffffff</color>
+
+    <dimen name="volume_slider_interspacing">2dp</dimen>
+    <dimen name="volume_offset_top">0dp</dimen>
+    <dimen name="volume_button_size">48dp</dimen>
+
+    <item name="volume_secondary_alpha" format="float" type="dimen">0.3</item>
+
+    <style name="VolumeDialogAnimations">
+        <item name="android:windowEnterAnimation">@android:anim/fade_in</item>
+        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
+    </style>
+
+    <style name="VolumeButtons" parent="@android:style/Widget.Material.Button.Borderless">
+        <item name="android:background">@drawable/btn_borderless_rect</item>
+    </style>
+
+    <style name="TextAppearance" />
+
+    <style name="TextAppearance.Volume">
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ffffffff</item>
+        <item name="android:fontFamily">sans-serif</item>
+    </style>
+
+    <style name="TextAppearance.Volume.ZenSwitch">
+        <item name="android:textSize">16sp</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="TextAppearance.Volume.ZenSwitchSummary">
+        <item name="android:textSize">14sp</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+    </style>
+
+    <style name="TextAppearance.Volume.ZenSwitchDetail">
+        <item name="android:textSize">14sp</item>
+        <item name="android:fontFamily">sans-serif</item>
+        <item name="android:textColor">#ffb0b3c5</item>
+    </style>
+
+    <string-array name="volume_stream_titles" translatable="false">
+        <item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
+        <item>System</item> <!-- STREAM_SYSTEM -->
+        <item>Notifications</item> <!-- STREAM_RING -->
+        <item>Media</item> <!-- STREAM_MUSIC -->
+        <item>Alarms</item> <!-- STREAM_ALARM -->
+        <item></item> <!-- STREAM_NOTIFICATION -->
+        <item>Bluetooth calls</item> <!-- STREAM_BLUETOOTH_SCO -->
+        <item></item> <!-- STREAM_SYSTEM_ENFORCED -->
+        <item></item> <!-- STREAM_DTMF -->
+        <item></item> <!-- STREAM_TTS -->
+    </string-array>
+
+    <string name="volume_dnd_is_on" translatable="false">Do not disturb is on</string>
+    <string name="volume_turn_off" translatable="false">Turn off</string>
+    <string name="volume_stream_muted" translatable="false">%s silent</string>
+    <string name="volume_stream_vibrate" translatable="false">%s vibrate</string>
+    <string name="volume_stream_suppressed" translatable="false">%1$s silent — %2$s</string>
+    <string name="volume_stream_muted_dnd" translatable="false">%s silent — No interruptions</string>
+    <string name="volume_stream_limited_dnd" translatable="false">%s — Priority only</string>
+    <string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
+    <string name="volume_dnd_ends_in" translatable="false">Do not disturb ends in %s</string>
+    <string name="volume_dnd_ends_at" translatable="false">Do not disturb ends at %s</string>
+    <string name="volume_end_now" translatable="false">End now</string>
+
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 2e95498..292c9c2 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui;
 
+import android.animation.ArgbEvaluator;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -80,6 +81,12 @@
     private BatteryController mBatteryController;
     private boolean mPowerSaveEnabled;
 
+    private int mDarkModeBackgroundColor;
+    private int mDarkModeFillColor;
+
+    private int mLightModeBackgroundColor;
+    private int mLightModeFillColor;
+
     private class BatteryTracker extends BroadcastReceiver {
         public static final int UNKNOWN_LEVEL = -1;
 
@@ -245,6 +252,13 @@
         mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
         mBoltPoints = loadBoltPoints(res);
+
+        mDarkModeBackgroundColor =
+                context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
+        mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
+        mLightModeBackgroundColor =
+                context.getColor(R.color.light_mode_icon_color_dual_tone_background);
+        mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
     }
 
     public void setBatteryController(BatteryController batteryController) {
@@ -309,14 +323,30 @@
         return color;
     }
 
-    public void setIconTint(int tint) {
-        mIconTint = tint;
-        mFramePaint.setColorFilter(new PorterDuffColorFilter(tint, PorterDuff.Mode.SRC_ATOP));
-        mBoltPaint.setColor(tint);
-        mChargeColor = tint;
+    public void setDarkIntensity(float darkIntensity) {
+        int backgroundColor = getBackgroundColor(darkIntensity);
+        int fillColor = getFillColor(darkIntensity);
+        mIconTint = fillColor;
+        mFramePaint.setColor(backgroundColor);
+        mBoltPaint.setColor(backgroundColor);
+        mChargeColor = fillColor;
         invalidate();
     }
 
+    private int getBackgroundColor(float darkIntensity) {
+        return getColorForDarkIntensity(
+                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+    }
+
+    private int getFillColor(float darkIntensity) {
+        return getColorForDarkIntensity(
+                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+    }
+
+    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+    }
+
     @Override
     public void draw(Canvas c) {
         BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
new file mode 100644
index 0000000..9df67fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.StringDef;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
+
+public final class Prefs {
+    private Prefs() {} // no instantation
+
+    @Retention(RetentionPolicy.SOURCE)
+    @StringDef({
+        Key.SEARCH_APP_WIDGET_ID,
+        Key.DEBUG_MODE_ENABLED,
+        Key.HOTSPOT_TILE_LAST_USED,
+        Key.COLOR_INVERSION_TILE_LAST_USED,
+        Key.DND_TILE_VISIBLE,
+        Key.DND_TILE_COMBINED_ICON
+    })
+    public @interface Key {
+        String SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
+        String DEBUG_MODE_ENABLED = "debugModeEnabled";
+        String HOTSPOT_TILE_LAST_USED = "HotspotTileLastUsed";
+        String COLOR_INVERSION_TILE_LAST_USED = "ColorInversionTileLastUsed";
+        String DND_TILE_VISIBLE = "DndTileVisible";
+        String DND_TILE_COMBINED_ICON = "DndTileCombinedIcon";
+    }
+
+    public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
+        return get(context).getBoolean(key, defaultValue);
+    }
+
+    public static void putBoolean(Context context, @Key String key, boolean value) {
+        get(context).edit().putBoolean(key, value).apply();
+    }
+
+    public static int getInt(Context context, @Key String key, int defaultValue) {
+        return get(context).getInt(key, defaultValue);
+    }
+
+    public static void putInt(Context context, @Key String key, int value) {
+        get(context).edit().putInt(key, value).apply();
+    }
+
+    public static long getLong(Context context, @Key String key, long defaultValue) {
+        return get(context).getLong(key, defaultValue);
+    }
+
+    public static void putLong(Context context, @Key String key, long value) {
+        get(context).edit().putLong(key, value).apply();
+    }
+
+    public static Map<String, ?> getAll(Context context) {
+        return get(context).getAll();
+    }
+
+    public static void remove(Context context, @Key String key) {
+        get(context).edit().remove(key).apply();
+    }
+
+    public static void registerListener(Context context,
+            OnSharedPreferenceChangeListener listener) {
+        get(context).registerOnSharedPreferenceChangeListener(listener);
+    }
+
+    public static void unregisterListener(Context context,
+            OnSharedPreferenceChangeListener listener) {
+        get(context).unregisterOnSharedPreferenceChangeListener(listener);
+    }
+
+    private static SharedPreferences get(Context context) {
+        return context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelCircleView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelCircleView.java
deleted file mode 100644
index f33e2b8..0000000
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelCircleView.java
+++ /dev/null
@@ -1,592 +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;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Outline;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewOutlineProvider;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-import android.view.animation.LinearInterpolator;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-import java.util.ArrayList;
-
-public class SearchPanelCircleView extends FrameLayout {
-
-    private final int mCircleMinSize;
-    private final int mBaseMargin;
-    private final int mStaticOffset;
-    private final Paint mBackgroundPaint = new Paint();
-    private final Paint mRipplePaint = new Paint();
-    private final Rect mCircleRect = new Rect();
-    private final Rect mStaticRect = new Rect();
-    private final Interpolator mFastOutSlowInInterpolator;
-    private final Interpolator mAppearInterpolator;
-    private final Interpolator mDisappearInterpolator;
-
-    private boolean mClipToOutline;
-    private final int mMaxElevation;
-    private boolean mAnimatingOut;
-    private float mOutlineAlpha;
-    private float mOffset;
-    private float mCircleSize;
-    private boolean mHorizontal;
-    private boolean mCircleHidden;
-    private ImageView mLogo;
-    private boolean mDraggedFarEnough;
-    private boolean mOffsetAnimatingIn;
-    private float mCircleAnimationEndValue;
-    private ArrayList<Ripple> mRipples = new ArrayList<Ripple>();
-
-    private ValueAnimator mOffsetAnimator;
-    private ValueAnimator mCircleAnimator;
-    private ValueAnimator mFadeOutAnimator;
-    private ValueAnimator.AnimatorUpdateListener mCircleUpdateListener
-            = new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            applyCircleSize((float) animation.getAnimatedValue());
-            updateElevation();
-        }
-    };
-    private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            mCircleAnimator = null;
-        }
-    };
-    private ValueAnimator.AnimatorUpdateListener mOffsetUpdateListener
-            = new ValueAnimator.AnimatorUpdateListener() {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            setOffset((float) animation.getAnimatedValue());
-        }
-    };
-
-
-    public SearchPanelCircleView(Context context) {
-        this(context, null);
-    }
-
-    public SearchPanelCircleView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchPanelCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public SearchPanelCircleView(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        setOutlineProvider(new ViewOutlineProvider() {
-            @Override
-            public void getOutline(View view, Outline outline) {
-                if (mCircleSize > 0.0f) {
-                    outline.setOval(mCircleRect);
-                } else {
-                    outline.setEmpty();
-                }
-                outline.setAlpha(mOutlineAlpha);
-            }
-        });
-        setWillNotDraw(false);
-        mCircleMinSize = context.getResources().getDimensionPixelSize(
-                R.dimen.search_panel_circle_size);
-        mBaseMargin = context.getResources().getDimensionPixelSize(
-                R.dimen.search_panel_circle_base_margin);
-        mStaticOffset = context.getResources().getDimensionPixelSize(
-                R.dimen.search_panel_circle_travel_distance);
-        mMaxElevation = context.getResources().getDimensionPixelSize(
-                R.dimen.search_panel_circle_elevation);
-        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.linear_out_slow_in);
-        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_slow_in);
-        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
-                android.R.interpolator.fast_out_linear_in);
-        mBackgroundPaint.setAntiAlias(true);
-        mBackgroundPaint.setColor(context.getColor(R.color.search_panel_circle_color));
-        mRipplePaint.setColor(context.getColor(R.color.search_panel_ripple_color));
-        mRipplePaint.setAntiAlias(true);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        drawBackground(canvas);
-        drawRipples(canvas);
-    }
-
-    private void drawRipples(Canvas canvas) {
-        for (int i = 0; i < mRipples.size(); i++) {
-            Ripple ripple = mRipples.get(i);
-            ripple.draw(canvas);
-        }
-    }
-
-    private void drawBackground(Canvas canvas) {
-        canvas.drawCircle(mCircleRect.centerX(), mCircleRect.centerY(), mCircleSize / 2,
-                mBackgroundPaint);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mLogo = (ImageView) findViewById(R.id.search_logo);
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        mLogo.layout(0, 0, mLogo.getMeasuredWidth(), mLogo.getMeasuredHeight());
-        if (changed) {
-            updateCircleRect(mStaticRect, mStaticOffset, true);
-        }
-    }
-
-    public void setCircleSize(float circleSize) {
-        setCircleSize(circleSize, false, null, 0, null);
-    }
-
-    public void setCircleSize(float circleSize, boolean animated, final Runnable endRunnable,
-            int startDelay, Interpolator interpolator) {
-        boolean isAnimating = mCircleAnimator != null;
-        boolean animationPending = isAnimating && !mCircleAnimator.isRunning();
-        boolean animatingOut = isAnimating && mCircleAnimationEndValue == 0;
-        if (animated || animationPending || animatingOut) {
-            if (isAnimating) {
-                if (circleSize == mCircleAnimationEndValue) {
-                    return;
-                }
-                mCircleAnimator.cancel();
-            }
-            mCircleAnimator = ValueAnimator.ofFloat(mCircleSize, circleSize);
-            mCircleAnimator.addUpdateListener(mCircleUpdateListener);
-            mCircleAnimator.addListener(mClearAnimatorListener);
-            mCircleAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (endRunnable != null) {
-                        endRunnable.run();
-                    }
-                }
-            });
-            Interpolator desiredInterpolator = interpolator != null ? interpolator
-                    : circleSize == 0 ? mDisappearInterpolator : mAppearInterpolator;
-            mCircleAnimator.setInterpolator(desiredInterpolator);
-            mCircleAnimator.setDuration(300);
-            mCircleAnimator.setStartDelay(startDelay);
-            mCircleAnimator.start();
-            mCircleAnimationEndValue = circleSize;
-        } else {
-            if (isAnimating) {
-                float diff = circleSize - mCircleAnimationEndValue;
-                PropertyValuesHolder[] values = mCircleAnimator.getValues();
-                values[0].setFloatValues(diff, circleSize);
-                mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime());
-                mCircleAnimationEndValue = circleSize;
-            } else {
-                applyCircleSize(circleSize);
-                updateElevation();
-            }
-        }
-    }
-
-    private void applyCircleSize(float circleSize) {
-        mCircleSize = circleSize;
-        updateLayout();
-    }
-
-    private void updateElevation() {
-        float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
-        t = 1.0f - Math.max(t, 0.0f);
-        float offset = t * mMaxElevation;
-        setElevation(offset);
-    }
-
-    /**
-     * Sets the offset to the edge of the screen. By default this not not animated.
-     *
-     * @param offset The offset to apply.
-     */
-    public void setOffset(float offset) {
-        setOffset(offset, false, 0, null, null);
-    }
-
-    /**
-     * Sets the offset to the edge of the screen.
-     *
-     * @param offset The offset to apply.
-     * @param animate Whether an animation should be performed.
-     * @param startDelay The desired start delay if animated.
-     * @param interpolator The desired interpolator if animated. If null,
-     *                     a default interpolator will be taken designed for appearing or
-     *                     disappearing.
-     * @param endRunnable The end runnable which should be executed when the animation is finished.
-     */
-    private void setOffset(float offset, boolean animate, int startDelay,
-            Interpolator interpolator, final Runnable endRunnable) {
-        if (!animate) {
-            mOffset = offset;
-            updateLayout();
-            if (endRunnable != null) {
-                endRunnable.run();
-            }
-        } else {
-            if (mOffsetAnimator != null) {
-                mOffsetAnimator.removeAllListeners();
-                mOffsetAnimator.cancel();
-            }
-            mOffsetAnimator = ValueAnimator.ofFloat(mOffset, offset);
-            mOffsetAnimator.addUpdateListener(mOffsetUpdateListener);
-            mOffsetAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mOffsetAnimator = null;
-                    if (endRunnable != null) {
-                        endRunnable.run();
-                    }
-                }
-            });
-            Interpolator desiredInterpolator = interpolator != null ?
-                    interpolator : offset == 0 ? mDisappearInterpolator : mAppearInterpolator;
-            mOffsetAnimator.setInterpolator(desiredInterpolator);
-            mOffsetAnimator.setStartDelay(startDelay);
-            mOffsetAnimator.setDuration(300);
-            mOffsetAnimator.start();
-            mOffsetAnimatingIn = offset != 0;
-        }
-    }
-
-    private void updateLayout() {
-        updateCircleRect();
-        updateLogo();
-        invalidateOutline();
-        invalidate();
-        updateClipping();
-    }
-
-    private void updateClipping() {
-        boolean clip = mCircleSize < mCircleMinSize || !mRipples.isEmpty();
-        if (clip != mClipToOutline) {
-            setClipToOutline(clip);
-            mClipToOutline = clip;
-        }
-    }
-
-    private void updateLogo() {
-        boolean exitAnimationRunning = mFadeOutAnimator != null;
-        Rect rect = exitAnimationRunning ? mCircleRect : mStaticRect;
-        float translationX = (rect.left + rect.right) / 2.0f - mLogo.getWidth() / 2.0f;
-        float translationY = (rect.top + rect.bottom) / 2.0f - mLogo.getHeight() / 2.0f;
-        float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
-        if (!exitAnimationRunning) {
-            if (mHorizontal) {
-                translationX += t * mStaticOffset * 0.3f;
-            } else {
-                translationY += t * mStaticOffset * 0.3f;
-            }
-            float alpha = 1.0f-t;
-            alpha = Math.max((alpha - 0.5f) * 2.0f, 0);
-            mLogo.setAlpha(alpha);
-        } else {
-            translationY += (mOffset - mStaticOffset) / 2;
-        }
-        mLogo.setTranslationX(translationX);
-        mLogo.setTranslationY(translationY);
-    }
-
-    private void updateCircleRect() {
-        updateCircleRect(mCircleRect, mOffset, false);
-    }
-
-    private void updateCircleRect(Rect rect, float offset, boolean useStaticSize) {
-        int left, top;
-        float circleSize = useStaticSize ? mCircleMinSize : mCircleSize;
-        if (mHorizontal) {
-            left = (int) (getWidth() - circleSize / 2 - mBaseMargin - offset);
-            top = (int) ((getHeight() - circleSize) / 2);
-        } else {
-            left = (int) (getWidth() - circleSize) / 2;
-            top = (int) (getHeight() - circleSize / 2 - mBaseMargin - offset);
-        }
-        rect.set(left, top, (int) (left + circleSize), (int) (top + circleSize));
-    }
-
-    public void setHorizontal(boolean horizontal) {
-        mHorizontal = horizontal;
-        updateCircleRect(mStaticRect, mStaticOffset, true);
-        updateLayout();
-    }
-
-    public void setDragDistance(float distance) {
-        if (!mAnimatingOut && (!mCircleHidden || mDraggedFarEnough)) {
-            float circleSize = mCircleMinSize + rubberband(distance);
-            setCircleSize(circleSize);
-        }
-
-    }
-
-    private float rubberband(float diff) {
-        return (float) Math.pow(Math.abs(diff), 0.6f);
-    }
-
-    public void startAbortAnimation(Runnable endRunnable) {
-        if (mAnimatingOut) {
-            if (endRunnable != null) {
-                endRunnable.run();
-            }
-            return;
-        }
-        setCircleSize(0, true, null, 0, null);
-        setOffset(0, true, 0, null, endRunnable);
-        mCircleHidden = true;
-    }
-
-    public void startEnterAnimation() {
-        if (mAnimatingOut) {
-            return;
-        }
-        applyCircleSize(0);
-        setOffset(0);
-        setCircleSize(mCircleMinSize, true, null, 50, null);
-        setOffset(mStaticOffset, true, 50, null, null);
-        mCircleHidden = false;
-    }
-
-
-    public void startExitAnimation(final Runnable endRunnable) {
-        if (!mHorizontal) {
-            float offset = getHeight() / 2.0f;
-            setOffset(offset - mBaseMargin, true, 50, mFastOutSlowInInterpolator, null);
-            float xMax = getWidth() / 2;
-            float yMax = getHeight() / 2;
-            float maxRadius = (float) Math.ceil(Math.hypot(xMax, yMax) * 2);
-            setCircleSize(maxRadius, true, null, 50, mFastOutSlowInInterpolator);
-            performExitFadeOutAnimation(50, 300, endRunnable);
-        } else {
-
-            // when in landscape, we don't wan't the animation as it interferes with the general
-            // rotation animation to the homescreen.
-            endRunnable.run();
-        }
-    }
-
-    private void performExitFadeOutAnimation(int startDelay, int duration,
-            final Runnable endRunnable) {
-        mFadeOutAnimator = ValueAnimator.ofFloat(mBackgroundPaint.getAlpha() / 255.0f, 0.0f);
-
-        // Linear since we are animating multiple values
-        mFadeOutAnimator.setInterpolator(new LinearInterpolator());
-        mFadeOutAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float animatedFraction = animation.getAnimatedFraction();
-                float logoValue = animatedFraction > 0.5f ? 1.0f : animatedFraction / 0.5f;
-                logoValue = PhoneStatusBar.ALPHA_OUT.getInterpolation(1.0f - logoValue);
-                float backgroundValue = animatedFraction < 0.2f ? 0.0f :
-                        PhoneStatusBar.ALPHA_OUT.getInterpolation((animatedFraction - 0.2f) / 0.8f);
-                backgroundValue = 1.0f - backgroundValue;
-                mBackgroundPaint.setAlpha((int) (backgroundValue * 255));
-                mOutlineAlpha = backgroundValue;
-                mLogo.setAlpha(logoValue);
-                invalidateOutline();
-                invalidate();
-            }
-        });
-        mFadeOutAnimator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (endRunnable != null) {
-                    endRunnable.run();
-                }
-                mLogo.setAlpha(1.0f);
-                mBackgroundPaint.setAlpha(255);
-                mOutlineAlpha = 1.0f;
-                mFadeOutAnimator = null;
-            }
-        });
-        mFadeOutAnimator.setStartDelay(startDelay);
-        mFadeOutAnimator.setDuration(duration);
-        mFadeOutAnimator.start();
-    }
-
-    public void setDraggedFarEnough(boolean farEnough) {
-        if (farEnough != mDraggedFarEnough) {
-            if (farEnough) {
-                if (mCircleHidden) {
-                    startEnterAnimation();
-                }
-                if (mOffsetAnimator == null) {
-                    addRipple();
-                } else {
-                    postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            addRipple();
-                        }
-                    }, 100);
-                }
-            } else {
-                startAbortAnimation(null);
-            }
-            mDraggedFarEnough = farEnough;
-        }
-
-    }
-
-    private void addRipple() {
-        if (mRipples.size() > 1) {
-            // we only want 2 ripples at the time
-            return;
-        }
-        float xInterpolation, yInterpolation;
-        if (mHorizontal) {
-            xInterpolation = 0.75f;
-            yInterpolation = 0.5f;
-        } else {
-            xInterpolation = 0.5f;
-            yInterpolation = 0.75f;
-        }
-        float circleCenterX = mStaticRect.left * (1.0f - xInterpolation)
-                + mStaticRect.right * xInterpolation;
-        float circleCenterY = mStaticRect.top * (1.0f - yInterpolation)
-                + mStaticRect.bottom * yInterpolation;
-        float radius = Math.max(mCircleSize, mCircleMinSize * 1.25f) * 0.75f;
-        Ripple ripple = new Ripple(circleCenterX, circleCenterY, radius);
-        ripple.start();
-    }
-
-    public void reset() {
-        mDraggedFarEnough = false;
-        mAnimatingOut = false;
-        mCircleHidden = true;
-        mClipToOutline = false;
-        if (mFadeOutAnimator != null) {
-            mFadeOutAnimator.cancel();
-        }
-        mBackgroundPaint.setAlpha(255);
-        mOutlineAlpha = 1.0f;
-    }
-
-    /**
-     * Check if an animation is currently running
-     *
-     * @param enterAnimation Is the animating queried the enter animation.
-     */
-    public boolean isAnimationRunning(boolean enterAnimation) {
-        return mOffsetAnimator != null && (enterAnimation == mOffsetAnimatingIn);
-    }
-
-    public void performOnAnimationFinished(final Runnable runnable) {
-        if (mOffsetAnimator != null) {
-            mOffsetAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    if (runnable != null) {
-                        runnable.run();
-                    }
-                }
-            });
-        } else {
-            if (runnable != null) {
-                runnable.run();
-            }
-        }
-    }
-
-    public void setAnimatingOut(boolean animatingOut) {
-        mAnimatingOut = animatingOut;
-    }
-
-    /**
-     * @return Whether the circle is currently launching to the search activity or aborting the
-     * interaction
-     */
-    public boolean isAnimatingOut() {
-        return mAnimatingOut;
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        // not really true but it's ok during an animation, as it's never permanent
-        return false;
-    }
-
-    private class Ripple {
-        float x;
-        float y;
-        float radius;
-        float endRadius;
-        float alpha;
-
-        Ripple(float x, float y, float endRadius) {
-            this.x = x;
-            this.y = y;
-            this.endRadius = endRadius;
-        }
-
-        void start() {
-            ValueAnimator animator = ValueAnimator.ofFloat(0.0f, 1.0f);
-
-            // Linear since we are animating multiple values
-            animator.setInterpolator(new LinearInterpolator());
-            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    alpha = 1.0f - animation.getAnimatedFraction();
-                    alpha = mDisappearInterpolator.getInterpolation(alpha);
-                    radius = mAppearInterpolator.getInterpolation(animation.getAnimatedFraction());
-                    radius *= endRadius;
-                    invalidate();
-                }
-            });
-            animator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mRipples.remove(Ripple.this);
-                    updateClipping();
-                }
-
-                public void onAnimationStart(Animator animation) {
-                    mRipples.add(Ripple.this);
-                    updateClipping();
-                }
-            });
-            animator.setDuration(400);
-            animator.start();
-        }
-
-        public void draw(Canvas canvas) {
-            mRipplePaint.setAlpha((int) (alpha * 255));
-            canvas.drawCircle(x, y, radius, mRipplePaint);
-        }
-    }
-
-}
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
deleted file mode 100644
index 445b499..0000000
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.app.ActivityOptions;
-import android.app.SearchManager;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.media.AudioAttributes;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.os.Vibrator;
-import android.provider.Settings;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-
-import com.android.systemui.statusbar.BaseStatusBar;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.StatusBarPanel;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-public class SearchPanelView extends FrameLayout implements StatusBarPanel {
-
-    private static final String TAG = "SearchPanelView";
-    private static final String ASSIST_ICON_METADATA_NAME =
-            "com.android.systemui.action_assist_icon";
-
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
-            .build();
-
-    private final Context mContext;
-    private BaseStatusBar mBar;
-
-    private SearchPanelCircleView mCircle;
-    private ImageView mLogo;
-    private View mScrim;
-
-    private int mThreshold;
-    private boolean mHorizontal;
-
-    private boolean mLaunching;
-    private boolean mDragging;
-    private boolean mDraggedFarEnough;
-    private float mStartTouch;
-    private float mStartDrag;
-    private boolean mLaunchPending;
-
-    public SearchPanelView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public SearchPanelView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        mContext = context;
-        mThreshold = context.getResources().getDimensionPixelSize(R.dimen.search_panel_threshold);
-    }
-
-    private void startAssistActivity() {
-        if (!mBar.isDeviceProvisioned()) return;
-
-        // Close Recent Apps if needed
-        mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
-
-        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
-        if (intent == null) return;
-
-        try {
-            final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                    R.anim.search_launch_enter, R.anim.search_launch_exit);
-            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            AsyncTask.execute(new Runnable() {
-                @Override
-                public void run() {
-                    mContext.startActivityAsUser(intent, opts.toBundle(),
-                            new UserHandle(UserHandle.USER_CURRENT));
-                }
-            });
-        } catch (ActivityNotFoundException e) {
-            Log.w(TAG, "Activity not found for " + intent.getAction());
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mCircle = (SearchPanelCircleView) findViewById(R.id.search_panel_circle);
-        mLogo = (ImageView) findViewById(R.id.search_logo);
-        mScrim = findViewById(R.id.search_panel_scrim);
-    }
-
-    private void maybeSwapSearchIcon() {
-        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                .getAssistIntent(mContext, false, UserHandle.USER_CURRENT);
-        if (intent != null) {
-            ComponentName component = intent.getComponent();
-            replaceDrawable(mLogo, component, ASSIST_ICON_METADATA_NAME);
-        } else {
-            mLogo.setImageDrawable(null);
-        }
-    }
-
-    public void replaceDrawable(ImageView v, ComponentName component, String name) {
-        if (component != null) {
-            try {
-                PackageManager packageManager = mContext.getPackageManager();
-                // Look for the search icon specified in the activity meta-data
-                Bundle metaData = packageManager.getActivityInfo(
-                        component, PackageManager.GET_META_DATA).metaData;
-                if (metaData != null) {
-                    int iconResId = metaData.getInt(name);
-                    if (iconResId != 0) {
-                        Resources res = packageManager.getResourcesForActivity(component);
-                        v.setImageDrawable(res.getDrawable(iconResId));
-                        return;
-                    }
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                Log.w(TAG, "Failed to swap drawable; "
-                        + component.flattenToShortString() + " not found", e);
-            } catch (Resources.NotFoundException nfe) {
-                Log.w(TAG, "Failed to swap drawable from "
-                        + component.flattenToShortString(), nfe);
-            }
-        }
-        v.setImageDrawable(null);
-    }
-
-    @Override
-    public boolean isInContentArea(int x, int y) {
-        return true;
-    }
-
-    private void vibrate() {
-        Context context = getContext();
-        if (Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0) {
-            Resources res = context.getResources();
-            Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
-            vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration),
-                    VIBRATION_ATTRIBUTES);
-        }
-    }
-
-    public void show(final boolean show, boolean animate) {
-        if (show) {
-            maybeSwapSearchIcon();
-            if (getVisibility() != View.VISIBLE) {
-                setVisibility(View.VISIBLE);
-                vibrate();
-                if (animate) {
-                    startEnterAnimation();
-                } else {
-                    mScrim.setAlpha(1f);
-                }
-            }
-            setFocusable(true);
-            setFocusableInTouchMode(true);
-            requestFocus();
-        } else {
-            if (animate) {
-                startAbortAnimation();
-            } else {
-                setVisibility(View.INVISIBLE);
-            }
-        }
-    }
-
-    private void startEnterAnimation() {
-        mCircle.startEnterAnimation();
-        mScrim.setAlpha(0f);
-        mScrim.animate()
-                .alpha(1f)
-                .setDuration(300)
-                .setStartDelay(50)
-                .setInterpolator(PhoneStatusBar.ALPHA_IN)
-                .start();
-
-    }
-
-    private void startAbortAnimation() {
-        mCircle.startAbortAnimation(new Runnable() {
-                    @Override
-                    public void run() {
-                        mCircle.setAnimatingOut(false);
-                        setVisibility(View.INVISIBLE);
-                    }
-                });
-        mCircle.setAnimatingOut(true);
-        mScrim.animate()
-                .alpha(0f)
-                .setDuration(300)
-                .setStartDelay(0)
-                .setInterpolator(PhoneStatusBar.ALPHA_OUT);
-    }
-
-    public void hide(boolean animate) {
-        if (mBar != null) {
-            // This will indirectly cause show(false, ...) to get called
-            mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
-        } else {
-            if (animate) {
-                startAbortAnimation();
-            } else {
-                setVisibility(View.INVISIBLE);
-            }
-        }
-    }
-
-    @Override
-    public boolean dispatchHoverEvent(MotionEvent event) {
-        // Ignore hover events outside of this panel bounds since such events
-        // generate spurious accessibility events with the panel content when
-        // tapping outside of it, thus confusing the user.
-        final int x = (int) event.getX();
-        final int y = (int) event.getY();
-        if (x >= 0 && x < getWidth() && y >= 0 && y < getHeight()) {
-            return super.dispatchHoverEvent(event);
-        }
-        return true;
-    }
-
-    /**
-     * Whether the panel is showing, or, if it's animating, whether it will be
-     * when the animation is done.
-     */
-    public boolean isShowing() {
-        return getVisibility() == View.VISIBLE && !mCircle.isAnimatingOut();
-    }
-
-    public void setBar(BaseStatusBar bar) {
-        mBar = bar;
-    }
-
-    public boolean isAssistantAvailable() {
-        return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mLaunching || mLaunchPending) {
-            return false;
-        }
-        int action = event.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN:
-                mStartTouch = mHorizontal ? event.getX() : event.getY();
-                mDragging = false;
-                mDraggedFarEnough = false;
-                mCircle.reset();
-                break;
-            case MotionEvent.ACTION_MOVE:
-                float currentTouch = mHorizontal ? event.getX() : event.getY();
-                if (getVisibility() == View.VISIBLE && !mDragging &&
-                        (!mCircle.isAnimationRunning(true /* enterAnimation */)
-                                || Math.abs(mStartTouch - currentTouch) > mThreshold)) {
-                    mStartDrag = currentTouch;
-                    mDragging = true;
-                }
-                if (mDragging) {
-                    float offset = Math.max(mStartDrag - currentTouch, 0.0f);
-                    mCircle.setDragDistance(offset);
-                    mDraggedFarEnough = Math.abs(mStartTouch - currentTouch) > mThreshold;
-                    mCircle.setDraggedFarEnough(mDraggedFarEnough);
-                }
-                break;
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                if (mDraggedFarEnough) {
-                    if (mCircle.isAnimationRunning(true  /* enterAnimation */)) {
-                        mLaunchPending = true;
-                        mCircle.setAnimatingOut(true);
-                        mCircle.performOnAnimationFinished(new Runnable() {
-                            @Override
-                            public void run() {
-                                startExitAnimation();
-                            }
-                        });
-                    } else {
-                        startExitAnimation();
-                    }
-                } else {
-                    startAbortAnimation();
-                }
-                break;
-        }
-        return true;
-    }
-
-    private void startExitAnimation() {
-        mLaunchPending = false;
-        if (mLaunching || getVisibility() != View.VISIBLE) {
-            return;
-        }
-        mLaunching = true;
-        startAssistActivity();
-        vibrate();
-        mCircle.setAnimatingOut(true);
-        mCircle.startExitAnimation(new Runnable() {
-                    @Override
-                    public void run() {
-                        mLaunching = false;
-                        mCircle.setAnimatingOut(false);
-                        setVisibility(View.INVISIBLE);
-                    }
-                });
-        mScrim.animate()
-                .alpha(0f)
-                .setDuration(300)
-                .setStartDelay(0)
-                .setInterpolator(PhoneStatusBar.ALPHA_OUT);
-    }
-
-    public void setHorizontal(boolean horizontal) {
-        mHorizontal = horizontal;
-        mCircle.setHorizontal(horizontal);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java
new file mode 100644
index 0000000..36be355
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java
@@ -0,0 +1,292 @@
+package com.android.systemui.assist;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.SearchManager;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.PixelFormat;
+import android.media.AudioAttributes;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ImageView;
+
+import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+
+/**
+ * Class to manage everything around the assist gesture.
+ */
+public class AssistGestureManager {
+
+    private static final String TAG = "AssistGestureManager";
+    private static final String ASSIST_ICON_METADATA_NAME =
+            "com.android.systemui.action_assist_icon";
+
+    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+            .build();
+
+    private static final long TIMEOUT_SERVICE = 2500;
+    private static final long TIMEOUT_ACTIVITY = 1000;
+
+    private final Context mContext;
+    private final WindowManager mWindowManager;
+    private AssistOrbContainer mView;
+    private final PhoneStatusBar mBar;
+    private final IVoiceInteractionManagerService mVoiceInteractionManagerService;
+
+    private IVoiceInteractionSessionShowCallback mShowCallback =
+            new IVoiceInteractionSessionShowCallback.Stub() {
+
+        @Override
+        public void onFailed() throws RemoteException {
+            mView.post(mHideRunnable);
+        }
+
+        @Override
+        public void onShown() throws RemoteException {
+            mView.post(mHideRunnable);
+        }
+    };
+
+    private Runnable mHideRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mView.removeCallbacks(this);
+            mView.show(false /* show */, true /* animate */);
+        }
+    };
+
+    public AssistGestureManager(PhoneStatusBar bar, Context context) {
+        mContext = context;
+        mBar = bar;
+        mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+        mVoiceInteractionManagerService = IVoiceInteractionManagerService.Stub.asInterface(
+                ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
+    }
+
+    public void onConfigurationChanged() {
+        boolean visible = false;
+        if (mView != null) {
+            visible = mView.isShowing();
+            mWindowManager.removeView(mView);
+        }
+
+        mView = (AssistOrbContainer) LayoutInflater.from(mContext).inflate(
+                R.layout.assist_orb, null);
+        mView.setVisibility(View.GONE);
+        mView.setSystemUiVisibility(
+                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
+        WindowManager.LayoutParams lp = getLayoutParams();
+        mWindowManager.addView(mView, lp);
+        mBar.getNavigationBarView().setDelegateView(mView);
+        if (visible) {
+            mView.show(true /* show */, false /* animate */);
+        }
+    }
+
+    public void onGestureInvoked(boolean vibrate) {
+        boolean isVoiceInteractorActive = getVoiceInteractorSupportsAssistGesture();
+        if (!isVoiceInteractorActive && !isAssistantIntentAvailable()) {
+            return;
+        }
+        if (vibrate) {
+            vibrate();
+        }
+        if (!isVoiceInteractorActive || !isVoiceSessionRunning()) {
+            showOrb();
+            mView.postDelayed(mHideRunnable, isVoiceInteractorActive
+                    ? TIMEOUT_SERVICE
+                    : TIMEOUT_ACTIVITY);
+        }
+        startAssist();
+    }
+
+    private WindowManager.LayoutParams getLayoutParams() {
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                mContext.getResources().getDimensionPixelSize(R.dimen.assist_orb_scrim_height),
+                WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING,
+                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
+                PixelFormat.TRANSLUCENT);
+        if (ActivityManager.isHighEndGfx()) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        }
+        lp.gravity = Gravity.BOTTOM | Gravity.START;
+        lp.setTitle("AssistPreviewPanel");
+        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
+                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+        return lp;
+    }
+
+    private void showOrb() {
+        maybeSwapSearchIcon();
+        mView.show(true /* show */, true /* animate */);
+    }
+
+    private void startAssist() {
+        if (getVoiceInteractorSupportsAssistGesture()) {
+            startVoiceInteractor();
+        } else {
+            startAssistActivity();
+        }
+    }
+
+    private void startAssistActivity() {
+        if (!mBar.isDeviceProvisioned()) {
+            return;
+        }
+
+        // Close Recent Apps if needed
+        mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL |
+                CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL);
+
+        final Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, true, UserHandle.USER_CURRENT);
+        if (intent == null) {
+            return;
+        }
+
+        try {
+            final ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+                    R.anim.search_launch_enter, R.anim.search_launch_exit);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            AsyncTask.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mContext.startActivityAsUser(intent, opts.toBundle(),
+                            new UserHandle(UserHandle.USER_CURRENT));
+                }
+            });
+        } catch (ActivityNotFoundException e) {
+            Log.w(TAG, "Activity not found for " + intent.getAction());
+        }
+    }
+
+    private void startVoiceInteractor() {
+        try {
+            mVoiceInteractionManagerService.showSessionForActiveService(mShowCallback);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call showSessionForActiveService", e);
+        }
+    }
+
+    private boolean getVoiceInteractorSupportsAssistGesture() {
+        try {
+            return mVoiceInteractionManagerService.activeServiceSupportsAssistGesture();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call activeServiceSupportsAssistGesture", e);
+            return false;
+        }
+    }
+
+    private ComponentName getVoiceInteractorComponentName() {
+        try {
+            return mVoiceInteractionManagerService.getActiveServiceComponentName();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call getActiveServiceComponentName", e);
+            return null;
+        }
+    }
+
+    private boolean isVoiceSessionRunning() {
+        try {
+            return mVoiceInteractionManagerService.isSessionRunning();
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to call isSessionRunning", e);
+            return false;
+        }
+    }
+
+    public void destroy() {
+        mWindowManager.removeViewImmediate(mView);
+    }
+
+    private void maybeSwapSearchIcon() {
+        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, false, UserHandle.USER_CURRENT);
+        ComponentName component = null;
+        boolean isService = false;
+        if (getVoiceInteractorSupportsAssistGesture()) {
+            component = getVoiceInteractorComponentName();
+            isService = true;
+        } else if (intent != null) {
+            component = intent.getComponent();
+        }
+        if (component != null) {
+            replaceDrawable(mView.getOrb().getLogo(), component, ASSIST_ICON_METADATA_NAME,
+                    isService);
+        } else {
+            mView.getOrb().getLogo().setImageDrawable(null);
+        }
+    }
+
+    public void replaceDrawable(ImageView v, ComponentName component, String name,
+            boolean isService) {
+        if (component != null) {
+            try {
+                PackageManager packageManager = mContext.getPackageManager();
+                // Look for the search icon specified in the activity meta-data
+                Bundle metaData = isService
+                        ? packageManager.getServiceInfo(
+                                component, PackageManager.GET_META_DATA).metaData
+                        : packageManager.getActivityInfo(
+                                component, PackageManager.GET_META_DATA).metaData;
+                if (metaData != null) {
+                    int iconResId = metaData.getInt(name);
+                    if (iconResId != 0) {
+                        Resources res = packageManager.getResourcesForApplication(
+                                component.getPackageName());
+                        v.setImageDrawable(res.getDrawable(iconResId));
+                        return;
+                    }
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, "Failed to swap drawable; "
+                        + component.flattenToShortString() + " not found", e);
+            } catch (Resources.NotFoundException nfe) {
+                Log.w(TAG, "Failed to swap drawable from "
+                        + component.flattenToShortString(), nfe);
+            }
+        }
+        v.setImageDrawable(null);
+    }
+
+    private void vibrate() {
+        if (Settings.System.getIntForUser(mContext.getContentResolver(),
+                Settings.System.HAPTIC_FEEDBACK_ENABLED, 1, UserHandle.USER_CURRENT) != 0) {
+            Resources res = mContext.getResources();
+            Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+            vibrator.vibrate(res.getInteger(R.integer.config_search_panel_view_vibration_duration),
+                    VIBRATION_ATTRIBUTES);
+        }
+    }
+
+    public boolean isAssistantIntentAvailable() {
+        return ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
+                .getAssistIntent(mContext, false, UserHandle.USER_CURRENT) != null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
new file mode 100644
index 0000000..67017db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbContainer.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.assist;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.FrameLayout;
+
+import com.android.systemui.R;
+
+public class AssistOrbContainer extends FrameLayout {
+
+    private static final long EXIT_START_DELAY = 150;
+
+    private final Interpolator mLinearOutSlowInInterpolator;
+    private final Interpolator mFastOutLinearInInterpolator;
+
+    private View mScrim;
+    private View mNavbarScrim;
+    private AssistOrbView mOrb;
+
+    private boolean mAnimatingOut;
+
+    public AssistOrbContainer(Context context) {
+        this(context, null);
+    }
+
+    public AssistOrbContainer(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AssistOrbContainer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                android.R.interpolator.linear_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                android.R.interpolator.fast_out_slow_in);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mScrim = findViewById(R.id.assist_orb_scrim);
+        mNavbarScrim = findViewById(R.id.assist_orb_navbar_scrim);
+        mOrb = (AssistOrbView) findViewById(R.id.assist_orb);
+    }
+
+    public void show(final boolean show, boolean animate) {
+        if (show) {
+            if (getVisibility() != View.VISIBLE) {
+                setVisibility(View.VISIBLE);
+                if (animate) {
+                    startEnterAnimation();
+                } else {
+                    reset();
+                }
+            }
+        } else {
+            if (animate) {
+                startExitAnimation(new Runnable() {
+                    @Override
+                    public void run() {
+                        mAnimatingOut = false;
+                        setVisibility(View.GONE);
+                    }
+                });
+            } else {
+                setVisibility(View.GONE);
+            }
+        }
+    }
+
+    private void reset() {
+        mAnimatingOut = false;
+        mOrb.reset();
+        mScrim.setAlpha(1f);
+        mNavbarScrim.setAlpha(1f);
+    }
+
+    private void startEnterAnimation() {
+        if (mAnimatingOut) {
+            return;
+        }
+        mOrb.startEnterAnimation();
+        mScrim.setAlpha(0f);
+        mNavbarScrim.setAlpha(0f);
+        post(new Runnable() {
+            @Override
+            public void run() {
+                mScrim.animate()
+                        .alpha(1f)
+                        .setDuration(300)
+                        .setStartDelay(0)
+                        .setInterpolator(mLinearOutSlowInInterpolator);
+                mNavbarScrim.animate()
+                        .alpha(1f)
+                        .setDuration(300)
+                        .setStartDelay(0)
+                        .setInterpolator(mLinearOutSlowInInterpolator);
+            }
+        });
+    }
+
+    private void startExitAnimation(final Runnable endRunnable) {
+        if (mAnimatingOut) {
+            if (endRunnable != null) {
+                endRunnable.run();
+            }
+            return;
+        }
+        mAnimatingOut = true;
+        mOrb.startExitAnimation(EXIT_START_DELAY);
+        mScrim.animate()
+                .alpha(0f)
+                .setDuration(250)
+                .setStartDelay(EXIT_START_DELAY)
+                .setInterpolator(mFastOutLinearInInterpolator);
+        mNavbarScrim.animate()
+                .alpha(0f)
+                .setDuration(250)
+                .setStartDelay(EXIT_START_DELAY)
+                .setInterpolator(mFastOutLinearInInterpolator)
+                .withEndAction(endRunnable);
+    }
+
+    /**
+     * Whether the panel is showing, or, if it's animating, whether it will be
+     * when the animation is done.
+     */
+    public boolean isShowing() {
+        return getVisibility() == View.VISIBLE && !mAnimatingOut;
+    }
+
+    public AssistOrbView getOrb() {
+        return mOrb;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
new file mode 100644
index 0000000..a3372a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistOrbView.java
@@ -0,0 +1,285 @@
+/*
+ * 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.assist;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.OvershootInterpolator;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+
+public class AssistOrbView extends FrameLayout {
+
+    private final int mCircleMinSize;
+    private final int mBaseMargin;
+    private final int mStaticOffset;
+    private final Paint mBackgroundPaint = new Paint();
+    private final Rect mCircleRect = new Rect();
+    private final Rect mStaticRect = new Rect();
+    private final Interpolator mAppearInterpolator;
+    private final Interpolator mDisappearInterpolator;
+    private final Interpolator mOvershootInterpolator = new OvershootInterpolator();
+
+    private boolean mClipToOutline;
+    private final int mMaxElevation;
+    private float mOutlineAlpha;
+    private float mOffset;
+    private float mCircleSize;
+    private ImageView mLogo;
+    private float mCircleAnimationEndValue;
+
+    private ValueAnimator mOffsetAnimator;
+    private ValueAnimator mCircleAnimator;
+
+    private ValueAnimator.AnimatorUpdateListener mCircleUpdateListener
+            = new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            applyCircleSize((float) animation.getAnimatedValue());
+            updateElevation();
+        }
+    };
+    private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCircleAnimator = null;
+        }
+    };
+    private ValueAnimator.AnimatorUpdateListener mOffsetUpdateListener
+            = new ValueAnimator.AnimatorUpdateListener() {
+        @Override
+        public void onAnimationUpdate(ValueAnimator animation) {
+            mOffset = (float) animation.getAnimatedValue();
+            updateLayout();
+        }
+    };
+
+
+    public AssistOrbView(Context context) {
+        this(context, null);
+    }
+
+    public AssistOrbView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public AssistOrbView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public AssistOrbView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setOutlineProvider(new ViewOutlineProvider() {
+            @Override
+            public void getOutline(View view, Outline outline) {
+                if (mCircleSize > 0.0f) {
+                    outline.setOval(mCircleRect);
+                } else {
+                    outline.setEmpty();
+                }
+                outline.setAlpha(mOutlineAlpha);
+            }
+        });
+        setWillNotDraw(false);
+        mCircleMinSize = context.getResources().getDimensionPixelSize(
+                R.dimen.assist_orb_size);
+        mBaseMargin = context.getResources().getDimensionPixelSize(
+                R.dimen.assist_orb_base_margin);
+        mStaticOffset = context.getResources().getDimensionPixelSize(
+                R.dimen.assist_orb_travel_distance);
+        mMaxElevation = context.getResources().getDimensionPixelSize(
+                R.dimen.assist_orb_elevation);
+        mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear_out_slow_in);
+        mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_linear_in);
+        mBackgroundPaint.setAntiAlias(true);
+        mBackgroundPaint.setColor(getResources().getColor(R.color.assist_orb_color));
+    }
+
+    public ImageView getLogo() {
+        return mLogo;
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        drawBackground(canvas);
+    }
+
+    private void drawBackground(Canvas canvas) {
+        canvas.drawCircle(mCircleRect.centerX(), mCircleRect.centerY(), mCircleSize / 2,
+                mBackgroundPaint);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mLogo = (ImageView) findViewById(R.id.search_logo);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        mLogo.layout(0, 0, mLogo.getMeasuredWidth(), mLogo.getMeasuredHeight());
+        if (changed) {
+            updateCircleRect(mStaticRect, mStaticOffset, true);
+        }
+    }
+
+    public void animateCircleSize(float circleSize, long duration,
+            long startDelay, Interpolator interpolator) {
+        if (circleSize == mCircleAnimationEndValue) {
+            return;
+        }
+        if (mCircleAnimator != null) {
+            mCircleAnimator.cancel();
+        }
+        mCircleAnimator = ValueAnimator.ofFloat(mCircleSize, circleSize);
+        mCircleAnimator.addUpdateListener(mCircleUpdateListener);
+        mCircleAnimator.addListener(mClearAnimatorListener);
+        mCircleAnimator.setInterpolator(interpolator);
+        mCircleAnimator.setDuration(duration);
+        mCircleAnimator.setStartDelay(startDelay);
+        mCircleAnimator.start();
+        mCircleAnimationEndValue = circleSize;
+    }
+
+    private void applyCircleSize(float circleSize) {
+        mCircleSize = circleSize;
+        updateLayout();
+    }
+
+    private void updateElevation() {
+        float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
+        t = 1.0f - Math.max(t, 0.0f);
+        float offset = t * mMaxElevation;
+        setElevation(offset);
+    }
+
+    /**
+     * Animates the offset to the edge of the screen.
+     *
+     * @param offset The offset to apply.
+     * @param startDelay The desired start delay if animated.
+     *
+     * @param interpolator The desired interpolator if animated. If null,
+     *                     a default interpolator will be taken designed for appearing or
+     *                     disappearing.
+     */
+    private void animateOffset(float offset, long duration, long startDelay,
+            Interpolator interpolator) {
+        if (mOffsetAnimator != null) {
+            mOffsetAnimator.removeAllListeners();
+            mOffsetAnimator.cancel();
+        }
+        mOffsetAnimator = ValueAnimator.ofFloat(mOffset, offset);
+        mOffsetAnimator.addUpdateListener(mOffsetUpdateListener);
+        mOffsetAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mOffsetAnimator = null;
+            }
+        });
+        mOffsetAnimator.setInterpolator(interpolator);
+        mOffsetAnimator.setStartDelay(startDelay);
+        mOffsetAnimator.setDuration(duration);
+        mOffsetAnimator.start();
+    }
+
+    private void updateLayout() {
+        updateCircleRect();
+        updateLogo();
+        invalidateOutline();
+        invalidate();
+        updateClipping();
+    }
+
+    private void updateClipping() {
+        boolean clip = mCircleSize < mCircleMinSize;
+        if (clip != mClipToOutline) {
+            setClipToOutline(clip);
+            mClipToOutline = clip;
+        }
+    }
+
+    private void updateLogo() {
+        float translationX = (mCircleRect.left + mCircleRect.right) / 2.0f - mLogo.getWidth() / 2.0f;
+        float translationY = (mCircleRect.top + mCircleRect.bottom) / 2.0f
+                - mLogo.getHeight() / 2.0f - mCircleMinSize / 7f;
+        float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
+        translationY += t * mStaticOffset * 0.1f;
+        float alpha = 1.0f-t;
+        alpha = Math.max((alpha - 0.5f) * 2.0f, 0);
+        mLogo.setImageAlpha((int) (alpha * 255));
+        mLogo.setTranslationX(translationX);
+        mLogo.setTranslationY(translationY);
+    }
+
+    private void updateCircleRect() {
+        updateCircleRect(mCircleRect, mOffset, false);
+    }
+
+    private void updateCircleRect(Rect rect, float offset, boolean useStaticSize) {
+        int left, top;
+        float circleSize = useStaticSize ? mCircleMinSize : mCircleSize;
+        left = (int) (getWidth() - circleSize) / 2;
+        top = (int) (getHeight() - circleSize / 2 - mBaseMargin - offset);
+        rect.set(left, top, (int) (left + circleSize), (int) (top + circleSize));
+    }
+
+    public void startExitAnimation(long delay) {
+        animateCircleSize(0, 200, delay, mDisappearInterpolator);
+        animateOffset(0, 200, delay, mDisappearInterpolator);
+    }
+
+    public void startEnterAnimation() {
+        applyCircleSize(0);
+        post(new Runnable() {
+            @Override
+            public void run() {
+                animateCircleSize(mCircleMinSize, 300, 0 /* delay */, mOvershootInterpolator);
+                animateOffset(mStaticOffset, 400, 0 /* delay */, mAppearInterpolator);
+            }
+        });
+    }
+
+    public void reset() {
+        mClipToOutline = false;
+        mBackgroundPaint.setAlpha(255);
+        mOutlineAlpha = 1.0f;
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        // not really true but it's ok during an animation, as it's never permanent
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index dd28734..d8e732e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -748,6 +748,11 @@
         synchronized (this) {
             if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
 
+            if (isSecure()) {
+                Log.d(TAG, "current mode is SecurityMode, ignore hide keyguard");
+                return;
+            }
+
             mExternallyEnabled = enabled;
 
             if (!enabled && mShowing) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java
index e60aa53..f36019b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.Listenable;
@@ -32,14 +33,15 @@
 
     private final Context mContext;
     private final long mTimeToShowTile;
-    private final String mPrefKey;
+    @Prefs.Key private final String mPrefKey;
     private final String mResetAction;
 
     private boolean mRegistered;
 
-    public UsageTracker(Context context, Class<?> tile, int timeoutResource) {
+    public UsageTracker(Context context, @Prefs.Key String prefKey, Class<?> tile,
+            int timeoutResource) {
         mContext = context;
-        mPrefKey = tile.getSimpleName() + "LastUsed";
+        mPrefKey = prefKey;
         mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources().getInteger(timeoutResource);
         mResetAction = "com.android.systemui.qs." + tile.getSimpleName() + ".usage_reset";
     }
@@ -56,16 +58,16 @@
     }
 
     public boolean isRecentlyUsed() {
-        long lastUsed = getSharedPrefs().getLong(mPrefKey, 0);
+        long lastUsed = Prefs.getLong(mContext, mPrefKey, 0L /* defaultValue */);
         return (System.currentTimeMillis() - lastUsed) < mTimeToShowTile;
     }
 
     public void trackUsage() {
-        getSharedPrefs().edit().putLong(mPrefKey, System.currentTimeMillis()).commit();
+        Prefs.putLong(mContext, mPrefKey, System.currentTimeMillis());
     }
 
     public void reset() {
-        getSharedPrefs().edit().remove(mPrefKey).commit();
+        Prefs.remove(mContext, mPrefKey);
     }
 
     public void showResetConfirmation(String title, final Runnable onConfirmed) {
@@ -87,10 +89,6 @@
         d.show();
     }
 
-    private SharedPreferences getSharedPrefs() {
-        return mContext.getSharedPreferences(mContext.getPackageName(), 0);
-    }
-
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
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 2dd02a5..2bc31fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -72,7 +72,7 @@
         final boolean airplaneMode = value != 0;
         state.value = airplaneMode;
         state.visible = true;
-        state.label = mContext.getString(R.string.quick_settings_airplane_mode_label);
+        state.label = mContext.getString(R.string.airplane_mode);
         if (airplaneMode) {
             state.icon = mEnable;
             state.contentDescription =  mContext.getString(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5963a45..4a33f55 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -18,6 +18,7 @@
 
 import android.provider.Settings.Secure;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.SecureSetting;
@@ -50,7 +51,8 @@
                 }
             }
         };
-        mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class,
+        mUsageTracker = new UsageTracker(host.getContext(),
+                Prefs.Key.COLOR_INVERSION_TILE_LAST_USED, ColorInversionTile.class,
                 R.integer.days_to_show_color_inversion_tile);
         if (mSetting.getValue() != 0 && !mUsageTracker.isRecentlyUsed()) {
             mUsageTracker.trackUsage();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 79600f5..6ce63d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.view.LayoutInflater;
@@ -28,6 +29,7 @@
 import android.view.View.OnAttachStateChangeListener;
 import android.view.ViewGroup;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -39,30 +41,35 @@
 
     private static final String ACTION_SET_VISIBLE = "com.android.systemui.dndtile.SET_VISIBLE";
     private static final String EXTRA_VISIBLE = "visible";
-    private static final String PREF_KEY_VISIBLE = "DndTileVisible";
 
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
 
     private boolean mListening;
-    private boolean mVisible;
     private boolean mShowingDetail;
 
     public DndTile(Host host) {
         super(host);
         mController = host.getZenModeController();
         mDetailAdapter = new DndDetailAdapter();
-        mVisible = getSharedPrefs(mContext).getBoolean(PREF_KEY_VISIBLE, false);
         mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_SET_VISIBLE));
     }
 
     public static void setVisible(Context context, boolean visible) {
-        context.sendBroadcast(new Intent(DndTile.ACTION_SET_VISIBLE)
-                .putExtra(DndTile.EXTRA_VISIBLE, visible));
+        Prefs.putBoolean(context, Prefs.Key.DND_TILE_VISIBLE, visible);
     }
 
     public static boolean isVisible(Context context) {
-        return getSharedPrefs(context).getBoolean(PREF_KEY_VISIBLE, false);
+        return Prefs.getBoolean(context, Prefs.Key.DND_TILE_VISIBLE, false /* defaultValue */);
+    }
+
+    public static void setCombinedIcon(Context context, boolean combined) {
+        Prefs.putBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON, combined);
+    }
+
+    public static boolean isCombinedIcon(Context context) {
+        return Prefs.getBoolean(context, Prefs.Key.DND_TILE_COMBINED_ICON,
+                false /* defaultValue */);
     }
 
     @Override
@@ -78,9 +85,9 @@
     @Override
     public void handleClick() {
         if (mState.value) {
-            mController.setZen(Global.ZEN_MODE_OFF);
+            mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
         } else {
-            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+            mController.setZen(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, null, TAG);
             showDetail(true);
         }
     }
@@ -89,7 +96,7 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
         state.value = zen != Global.ZEN_MODE_OFF;
-        state.visible = mVisible;
+        state.visible = isVisible(mContext);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
@@ -103,6 +110,12 @@
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_dnd_none_on);
                 break;
+            case Global.ZEN_MODE_ALARMS:
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_on);
+                state.label = mContext.getString(R.string.quick_settings_dnd_alarms_label);
+                state.contentDescription = mContext.getString(
+                        R.string.accessibility_quick_settings_dnd_alarms_on);
+                break;
             default:
                 state.icon = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
                 state.label = mContext.getString(R.string.quick_settings_dnd_label);
@@ -130,26 +143,36 @@
         mListening = listening;
         if (mListening) {
             mController.addCallback(mZenCallback);
+            Prefs.registerListener(mContext, mPrefListener);
         } else {
             mController.removeCallback(mZenCallback);
+            Prefs.unregisterListener(mContext, mPrefListener);
         }
     }
 
+    private final OnSharedPreferenceChangeListener mPrefListener
+            = new OnSharedPreferenceChangeListener() {
+        @Override
+        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+                @Prefs.Key String key) {
+            if (Prefs.Key.DND_TILE_COMBINED_ICON.equals(key) ||
+                    Prefs.Key.DND_TILE_VISIBLE.equals(key)) {
+                refreshState();
+            }
+        }
+    };
+
     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
         public void onZenChanged(int zen) {
             refreshState(zen);
         }
     };
 
-    private static SharedPreferences getSharedPrefs(Context context) {
-        return context.getSharedPreferences(context.getPackageName(), 0);
-    }
-
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            mVisible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
-            getSharedPrefs(mContext).edit().putBoolean(PREF_KEY_VISIBLE, mVisible).commit();
+            final boolean visible = intent.getBooleanExtra(EXTRA_VISIBLE, false);
+            setVisible(mContext, visible);
             refreshState();
         }
     };
@@ -174,7 +197,7 @@
         @Override
         public void setToggleState(boolean state) {
             if (!state) {
-                mController.setZen(Global.ZEN_MODE_OFF);
+                mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
                 showDetail(false);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index fcc517f..6063f80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.qs.UsageTracker;
 import com.android.systemui.qs.QSTile;
@@ -105,7 +106,8 @@
     }
 
     private static UsageTracker newUsageTracker(Context context) {
-        return new UsageTracker(context, HotspotTile.class, R.integer.days_to_show_hotspot_tile);
+        return new UsageTracker(context, Prefs.Key.HOTSPOT_TILE_LAST_USED, HotspotTile.class,
+                R.integer.days_to_show_hotspot_tile);
     }
 
     private final class Callback implements HotspotController.Callback {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 192acc6..c7f8919 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -59,8 +59,6 @@
     public static class Values {
         public static class App {
             public static int AppWidgetHostId = 1024;
-            public static String Key_SearchAppWidgetId = "searchAppWidgetId";
-            public static String Key_DebugModeEnabled = "debugModeEnabled";
             public static String DebugModeVersion = "A";
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index f014f09..1001feb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -19,14 +19,12 @@
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.SearchManager;
-import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -36,6 +34,7 @@
 import android.view.ViewStub;
 import android.widget.Toast;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.DebugTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
@@ -49,8 +48,6 @@
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.recents.views.ViewAnimation;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-import com.android.systemui.SystemUIApplication;
 
 import java.lang.ref.WeakReference;
 import java.lang.reflect.InvocationTargetException;
@@ -78,9 +75,9 @@
     RecentsResizeTaskDialog mResizeTaskDebugDialog;
 
     // Search AppWidget
-    RecentsAppWidgetHost mAppWidgetHost;
     AppWidgetProviderInfo mSearchAppWidgetInfo;
-    AppWidgetHostView mSearchAppWidgetHostView;
+    RecentsAppWidgetHost mAppWidgetHost;
+    RecentsAppWidgetHostView mSearchAppWidgetHostView;
 
     // Runnables to finish the Recents activity
     FinishRecentsRunnable mFinishLaunchHomeRunnable;
@@ -245,7 +242,7 @@
             if (mEmptyView != null) {
                 mEmptyView.setVisibility(View.GONE);
             }
-            if (mRecentsView.hasSearchBar()) {
+            if (mRecentsView.hasValidSearchBar()) {
                 mRecentsView.setSearchBarVisibility(View.VISIBLE);
             } else {
                 addSearchBarAppWidgetView();
@@ -295,8 +292,8 @@
         if (Constants.DebugFlags.App.EnableSearchLayout) {
             int appWidgetId = mConfig.searchBarAppWidgetId;
             if (appWidgetId >= 0) {
-                mSearchAppWidgetHostView = mAppWidgetHost.createView(this, appWidgetId,
-                        mSearchAppWidgetInfo);
+                mSearchAppWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView(
+                        this, appWidgetId, mSearchAppWidgetInfo);
                 Bundle opts = new Bundle();
                 opts.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
                         AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
@@ -345,6 +342,12 @@
         }
     }
 
+    /** Dismisses Recents directly to Home without transition animation. */
+    void dismissRecentsToHomeWithoutTransitionAnimation() {
+        finish();
+        overridePendingTransition(0, 0);
+    }
+
     /** Dismisses Recents directly to Home if we currently aren't transitioning. */
     boolean dismissRecentsToHome(boolean animated) {
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
@@ -563,10 +566,9 @@
     /** Called when debug mode is triggered */
     public void onDebugModeTriggered() {
         if (mConfig.developerOptionsEnabled) {
-            SharedPreferences settings = getSharedPreferences(getPackageName(), 0);
-            if (settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false)) {
+            if (Prefs.getBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, false /* boolean */)) {
                 // Disable the debug mode
-                settings.edit().remove(Constants.Values.App.Key_DebugModeEnabled).apply();
+                Prefs.remove(this, Prefs.Key.DEBUG_MODE_ENABLED);
                 mConfig.debugModeEnabled = false;
                 inflateDebugOverlay();
                 if (mDebugOverlay != null) {
@@ -574,7 +576,7 @@
                 }
             } else {
                 // Enable the debug mode
-                settings.edit().putBoolean(Constants.Values.App.Key_DebugModeEnabled, true).apply();
+                Prefs.putBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, true);
                 mConfig.debugModeEnabled = true;
                 inflateDebugOverlay();
                 if (mDebugOverlay != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index 5bae37a..02a7b94 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents;
 
 import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -61,6 +62,12 @@
     }
 
     @Override
+    protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+                                             AppWidgetProviderInfo appWidget) {
+        return new RecentsAppWidgetHostView(context);
+    }
+
+    @Override
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
         if (mCb == null) return;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
new file mode 100644
index 0000000..1ed755a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHostView.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import android.appwidget.AppWidgetHostView;
+import android.content.Context;
+import android.widget.RemoteViews;
+
+public class RecentsAppWidgetHostView extends AppWidgetHostView {
+
+    private Context mContext;
+    private int mPreviousOrientation;
+
+    public RecentsAppWidgetHostView(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void updateAppWidget(RemoteViews remoteViews) {
+        // Store the orientation in which the widget was inflated
+        updateLastInflationOrientation();
+        super.updateAppWidget(remoteViews);
+    }
+
+    /**
+     * Updates the last orientation that this widget was inflated.
+     */
+    private void updateLastInflationOrientation() {
+        mPreviousOrientation = mContext.getResources().getConfiguration().orientation;
+    }
+
+    /**
+     * @return whether the search widget was updated while Recents was in a different orientation
+     *         in the background.
+     */
+    public boolean isReinflateRequired() {
+        // Re-inflate is required if the orientation has changed since last inflated.
+        int orientation = mContext.getResources().getConfiguration().orientation;
+        if (mPreviousOrientation != orientation) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index abeb2b0..244fada 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -18,7 +18,6 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
@@ -26,6 +25,8 @@
 import android.util.DisplayMetrics;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -177,12 +178,12 @@
 
     /** Updates the state, given the specified context */
     void update(Context context) {
-        SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
         Resources res = context.getResources();
         DisplayMetrics dm = res.getDisplayMetrics();
 
         // Debug mode
-        debugModeEnabled = settings.getBoolean(Constants.Values.App.Key_DebugModeEnabled, false);
+        debugModeEnabled = Prefs.getBoolean(context, Prefs.Key.DEBUG_MODE_ENABLED,
+                false /* defaultValue */);
         if (debugModeEnabled) {
             Console.Enabled = true;
         }
@@ -206,7 +207,8 @@
 
         // Search Bar
         searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-        searchBarAppWidgetId = settings.getInt(Constants.Values.App.Key_SearchAppWidgetId, -1);
+        searchBarAppWidgetId = Prefs.getInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID,
+                -1 /* defaultValue */);
 
         // Task stack
         taskStackScrollDuration =
@@ -280,9 +282,7 @@
     /** Updates the search bar app widget */
     public void updateSearchBarAppWidgetId(Context context, int appWidgetId) {
         searchBarAppWidgetId = appWidgetId;
-        SharedPreferences settings = context.getSharedPreferences(context.getPackageName(), 0);
-        settings.edit().putInt(Constants.Values.App.Key_SearchAppWidgetId,
-                appWidgetId).apply();
+        Prefs.putInt(context, Prefs.Key.SEARCH_APP_WIDGET_ID, appWidgetId);
     }
 
     /** Updates the states that need to be re-read whenever we re-initialize. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 4cd577d..b701e0b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -209,6 +209,10 @@
             }
         }
 
+        // Get rid of the dialog.
+        dismiss();
+        mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
+
         // Resize all tasks beginning from the "oldest" one.
         for (int i = additionalTasks; i >= 0; --i) {
             if (mTasks[i] != null) {
@@ -216,12 +220,8 @@
             }
         }
 
-        // Get rid of the dialog.
-        dismiss();
-        mRecentsActivity.dismissRecentsToHomeRaw(false);
-
-        // Show tasks - beginning with the oldest so that the focus ends on the selected one.
-        // TODO: Remove this once issue b/19893373 is resolved.
+        // Show tasks as they might not be currently visible - beginning with the oldest so that
+        // the focus ends on the selected one.
         for (int i = additionalTasks; i >= 0; --i) {
             if (mTasks[i] != null) {
                 mRecentsView.launchTask(mTasks[i]);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index abed7a5..1377975 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -34,6 +34,7 @@
 import android.widget.FrameLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsAppWidgetHostView;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsPackageMonitor;
@@ -69,7 +70,7 @@
 
     ArrayList<TaskStack> mStacks;
     List<TaskStackView> mTaskStackViews = new ArrayList<>();
-    View mSearchBar;
+    RecentsAppWidgetHostView mSearchBar;
     RecentsViewCallbacks mCb;
 
     public RecentsView(Context context) {
@@ -278,7 +279,7 @@
     }
 
     /** Adds the search bar */
-    public void setSearchBar(View searchBar) {
+    public void setSearchBar(RecentsAppWidgetHostView searchBar) {
         // Create the search bar (and hide it if we have no recent tasks)
         if (Constants.DebugFlags.App.EnableSearchLayout) {
             // Remove the previous search bar if one exists
@@ -294,8 +295,8 @@
     }
 
     /** Returns whether there is currently a search bar */
-    public boolean hasSearchBar() {
-        return mSearchBar != null;
+    public boolean hasValidSearchBar() {
+        return mSearchBar != null && !mSearchBar.isReinflateRequired();
     }
 
     /** Sets the visibility of the search bar */
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9d349ab..105bf0f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -122,7 +122,7 @@
 
         // Prepare all the output metadata
         mImageTime = System.currentTimeMillis();
-        String imageDate = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date(mImageTime));
+        String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
         mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
 
         mScreenshotDir = new File(Environment.getExternalStoragePublicDirectory(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 55bdcac..d2837b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -71,7 +71,6 @@
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -79,7 +78,6 @@
 import android.view.animation.AnimationUtils;
 import android.widget.DateTimeView;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
@@ -90,7 +88,6 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
-import com.android.systemui.SearchPanelView;
 import com.android.systemui.SwipeHelper;
 import com.android.systemui.SystemUI;
 import com.android.systemui.recents.Recents;
@@ -132,7 +129,6 @@
     protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023;
     protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
     protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
-    protected static final int MSG_CLOSE_SEARCH_PANEL = 1027;
     protected static final int MSG_SHOW_HEADS_UP = 1028;
     protected static final int MSG_HIDE_HEADS_UP = 1029;
     protected static final int MSG_ESCALATE_HEADS_UP = 1030;
@@ -164,9 +160,6 @@
     protected HeadsUpNotificationView mHeadsUpNotificationView;
     protected int mHeadsUpNotificationDecay;
 
-    // Search panel
-    protected SearchPanelView mSearchPanelView;
-
     protected int mCurrentUserId = 0;
     final protected SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
 
@@ -1043,50 +1036,6 @@
         mHandler.sendEmptyMessage(msg);
     }
 
-    @Override
-    public void showSearchPanel() {
-        if (mSearchPanelView != null && mSearchPanelView.isAssistantAvailable()) {
-            mSearchPanelView.show(true, true);
-        }
-    }
-
-    @Override
-    public void hideSearchPanel() {
-        int msg = MSG_CLOSE_SEARCH_PANEL;
-        mHandler.removeMessages(msg);
-        mHandler.sendEmptyMessage(msg);
-    }
-
-    protected abstract WindowManager.LayoutParams getSearchLayoutParams(
-            LayoutParams layoutParams);
-
-    protected void updateSearchPanel() {
-        // Search Panel
-        boolean visible = false;
-        if (mSearchPanelView != null) {
-            visible = mSearchPanelView.isShowing();
-            mWindowManager.removeView(mSearchPanelView);
-        }
-
-        // Provide SearchPanel with a temporary parent to allow layout params to work.
-        LinearLayout tmpRoot = new LinearLayout(mContext);
-        mSearchPanelView = (SearchPanelView) LayoutInflater.from(mContext).inflate(
-                 R.layout.status_bar_search_panel, tmpRoot, false);
-        mSearchPanelView.setOnTouchListener(
-                 new TouchOutsideListener(MSG_CLOSE_SEARCH_PANEL, mSearchPanelView));
-        mSearchPanelView.setVisibility(View.GONE);
-        boolean vertical = mNavigationBarView != null && mNavigationBarView.isVertical();
-        mSearchPanelView.setHorizontal(vertical);
-
-        WindowManager.LayoutParams lp = getSearchLayoutParams(mSearchPanelView.getLayoutParams());
-
-        mWindowManager.addView(mSearchPanelView, lp);
-        mSearchPanelView.setBar(this);
-        if (visible) {
-            mSearchPanelView.show(true, false);
-        }
-    }
-
     protected H createHandler() {
          return new H();
     }
@@ -1263,38 +1212,10 @@
              case MSG_SHOW_PREV_AFFILIATED_TASK:
                   showRecentsPreviousAffiliatedTask();
                   break;
-             case MSG_CLOSE_SEARCH_PANEL:
-                 if (DEBUG) Log.d(TAG, "closing search panel");
-                 if (mSearchPanelView != null && mSearchPanelView.isShowing()) {
-                     mSearchPanelView.show(false, true);
-                 }
-                 break;
             }
         }
     }
 
-    public class TouchOutsideListener implements View.OnTouchListener {
-        private int mMsg;
-        private StatusBarPanel mPanel;
-
-        public TouchOutsideListener(int msg, StatusBarPanel panel) {
-            mMsg = msg;
-            mPanel = panel;
-        }
-
-        public boolean onTouch(View v, MotionEvent ev) {
-            final int action = ev.getAction();
-            if (action == MotionEvent.ACTION_OUTSIDE
-                || (action == MotionEvent.ACTION_DOWN
-                    && !mPanel.isInContentArea((int)ev.getX(), (int)ev.getY()))) {
-                mHandler.removeMessages(mMsg);
-                mHandler.sendEmptyMessage(mMsg);
-                return true;
-            }
-            return false;
-        }
-    }
-
     protected void workAroundBadLayerDrawableOpacity(View v) {
     }
 
@@ -1707,7 +1628,7 @@
 
                     // close the shade if it was open
                     animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
-                            true /* force */);
+                            true /* force */, true /* delayed */);
                     visibilityChanged(false);
 
                     return mIntent != null && mIntent.isActivity();
@@ -1719,6 +1640,9 @@
     public void animateCollapsePanels(int flags, boolean force) {
     }
 
+    public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
+    }
+
     public void overrideActivityPendingAppTransition(boolean keyguardShowing) {
         if (keyguardShowing) {
             try {
@@ -1935,7 +1859,7 @@
 
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotifications();
-    protected abstract boolean shouldDisableNavbarGestures();
+    public abstract boolean shouldDisableNavbarGestures();
 
     public abstract void addNotification(StatusBarNotification notification,
             RankingMap ranking, Entry oldEntry);
@@ -2241,9 +2165,6 @@
     }
 
     public void destroy() {
-        if (mSearchPanelView != null) {
-            mWindowManager.removeViewImmediate(mSearchPanelView);
-        }
         mContext.unregisterReceiver(mBroadcastReceiver);
         try {
             mNotificationListener.unregisterAsSystemService();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 8f88e73d..7aa9a90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -96,8 +96,6 @@
         public void toggleRecentApps();
         public void preloadRecentApps();
         public void cancelPreloadRecentApps();
-        public void showSearchPanel();
-        public void hideSearchPanel();
         public void setWindowState(int window, int state);
         public void buzzBeepBlinked();
         public void notificationLightOff();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 7ae6764..9e2207e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -22,11 +22,12 @@
 import android.view.MotionEvent;
 import android.view.View;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 public class DelegateViewHelper {
     private View mDelegateView;
     private View mSourceView;
-    private BaseStatusBar mBar;
+    private PhoneStatusBar mBar;
     private int[] mTempPoint = new int[2];
     private float[] mDownPoint = new float[2];
     private float mTriggerThreshhold;
@@ -45,7 +46,7 @@
         mDelegateView = view;
     }
 
-    public void setBar(BaseStatusBar phoneStatusBar) {
+    public void setBar(PhoneStatusBar phoneStatusBar) {
         mBar = phoneStatusBar;
     }
 
@@ -79,7 +80,7 @@
                 float y = k < historySize ? event.getHistoricalY(k) : event.getY();
                 final float distance = mSwapXY ? (mDownPoint[0] - x) : (mDownPoint[1] - y);
                 if (distance > mTriggerThreshhold) {
-                    mBar.showSearchPanel();
+                    mBar.invokeAssistGesture(false /* vibrate */);
                     mPanelShowing = true;
                     break;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index e2464c2..583184f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -34,6 +34,7 @@
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.KeyguardAffordanceHelper;
 
 /**
  * An ImageView which does not have overlapping renderings commands and therefore does not need a
@@ -75,6 +76,7 @@
     private float mCircleStartRadius;
     private float mMaxCircleSize;
     private Animator mPreviewClipper;
+    private float mRestingAlpha = KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT;
     private AnimatorListenerAdapter mClipEndListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
@@ -394,6 +396,17 @@
         }
     }
 
+    public void setRestingAlpha(float alpha) {
+        mRestingAlpha = alpha;
+
+        // TODO: Handle the case an animation is playing.
+        setImageAlpha(alpha, false);
+    }
+
+    public float getRestingAlpha() {
+        return mRestingAlpha;
+    }
+
     public void setImageAlpha(float alpha, boolean animate) {
         setImageAlpha(alpha, animate, -1, null, null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 58067c3..07a055c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.Color;
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Handler;
@@ -53,6 +54,7 @@
 
     private String mRestingIndication;
     private String mTransientIndication;
+    private int mTransientTextColor;
     private boolean mVisible;
 
     private boolean mPowerPluggedIn;
@@ -105,7 +107,15 @@
      * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
      */
     public void showTransientIndication(String transientIndication) {
+        showTransientIndication(transientIndication, Color.WHITE);
+    }
+
+    /**
+     * Shows {@param transientIndication} until it is hidden by {@link #hideTransientIndication}.
+     */
+    public void showTransientIndication(String transientIndication, int textColor) {
         mTransientIndication = transientIndication;
+        mTransientTextColor = textColor;
         mHandler.removeMessages(MSG_HIDE_TRANSIENT);
         updateIndication();
     }
@@ -124,9 +134,17 @@
     private void updateIndication() {
         if (mVisible) {
             mTextView.switchIndication(computeIndication());
+            mTextView.setTextColor(computeColor());
         }
     }
 
+    private int computeColor() {
+        if (!TextUtils.isEmpty(mTransientIndication)) {
+            return mTransientTextColor;
+        }
+        return Color.WHITE;
+    }
+
     private String computeIndication() {
         if (!TextUtils.isEmpty(mTransientIndication)) {
             return mTransientIndication;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 7286907..a82afcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -59,9 +59,10 @@
     private String mWifiDescription;
     private ArrayList<PhoneState> mPhoneStates = new ArrayList<PhoneState>();
     private int mIconTint = Color.WHITE;
+    private float mDarkIntensity;
 
     ViewGroup mWifiGroup;
-    ImageView mVpn, mWifi, mAirplane, mNoSims;
+    ImageView mVpn, mWifi, mAirplane, mNoSims, mWifiDark, mNoSimsDark;
     View mWifiAirplaneSpacer;
     View mWifiSignalSpacer;
     LinearLayout mMobileSignalGroup;
@@ -115,8 +116,10 @@
         mVpn            = (ImageView) findViewById(R.id.vpn);
         mWifiGroup      = (ViewGroup) findViewById(R.id.wifi_combo);
         mWifi           = (ImageView) findViewById(R.id.wifi_signal);
+        mWifiDark       = (ImageView) findViewById(R.id.wifi_signal_dark);
         mAirplane       = (ImageView) findViewById(R.id.airplane);
         mNoSims         = (ImageView) findViewById(R.id.no_sims);
+        mNoSimsDark     = (ImageView) findViewById(R.id.no_sims_dark);
         mWifiAirplaneSpacer =         findViewById(R.id.wifi_airplane_spacer);
         mWifiSignalSpacer =           findViewById(R.id.wifi_signal_spacer);
         mMobileSignalGroup = (LinearLayout) findViewById(R.id.mobile_signal_group);
@@ -273,6 +276,7 @@
         if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
         if (mWifiVisible) {
             mWifi.setImageResource(mWifiStrengthId);
+            mWifiDark.setImageResource(mWifiStrengthId);
             mWifiGroup.setContentDescription(mWifiDescription);
             mWifiGroup.setVisibility(View.VISIBLE);
         } else {
@@ -317,15 +321,17 @@
         }
 
         mNoSims.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
+        mNoSimsDark.setVisibility(mNoSimsVisible ? View.VISIBLE : View.GONE);
 
         boolean anythingVisible = mNoSimsVisible || mWifiVisible || mIsAirplaneMode
                 || anyMobileVisible || mVpnVisible;
         setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0);
     }
 
-    public void setIconTint(int tint) {
-        boolean changed = tint != mIconTint;
+    public void setIconTint(int tint, float darkIntensity) {
+        boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity;
         mIconTint = tint;
+        mDarkIntensity = darkIntensity;
         if (changed && isAttachedToWindow()) {
             applyIconTint();
         }
@@ -333,14 +339,19 @@
 
     private void applyIconTint() {
         setTint(mVpn, mIconTint);
-        setTint(mWifi, mIconTint);
-        setTint(mNoSims, mIconTint);
         setTint(mAirplane, mIconTint);
+        applyDarkIntensity(mDarkIntensity, mNoSims, mNoSimsDark);
+        applyDarkIntensity(mDarkIntensity, mWifi, mWifiDark);
         for (int i = 0; i < mPhoneStates.size(); i++) {
-            mPhoneStates.get(i).setIconTint(mIconTint);
+            mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity);
         }
     }
 
+    private void applyDarkIntensity(float darkIntensity, View lightIcon, View darkIcon) {
+        lightIcon.setAlpha(1 - darkIntensity);
+        darkIcon.setAlpha(darkIntensity);
+    }
+
     private void setTint(ImageView v, int tint) {
         v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
         v.setImageTintList(ColorStateList.valueOf(tint));
@@ -354,7 +365,7 @@
         private String mMobileDescription, mMobileTypeDescription;
 
         private ViewGroup mMobileGroup;
-        private ImageView mMobile, mMobileType;
+        private ImageView mMobile, mMobileDark, mMobileType;
 
         public PhoneState(int subId, Context context) {
             ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -366,12 +377,14 @@
         public void setViews(ViewGroup root) {
             mMobileGroup    = root;
             mMobile         = (ImageView) root.findViewById(R.id.mobile_signal);
+            mMobileDark     = (ImageView) root.findViewById(R.id.mobile_signal_dark);
             mMobileType     = (ImageView) root.findViewById(R.id.mobile_type);
         }
 
         public boolean apply(boolean isSecondaryIcon) {
             if (mMobileVisible && !mIsAirplaneMode) {
                 mMobile.setImageResource(mMobileStrengthId);
+                mMobileDark.setImageResource(mMobileStrengthId);
                 mMobileType.setImageResource(mMobileTypeId);
                 mMobileGroup.setContentDescription(mMobileTypeDescription
                         + " " + mMobileDescription);
@@ -385,6 +398,8 @@
                     0, 0, 0);
             mMobile.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
                     0, 0, 0);
+            mMobileDark.setPaddingRelative(mIsMobileTypeIconWide ? mWideTypeIconStartPadding : 0,
+                    0, 0, 0);
 
             if (DEBUG) Log.d(TAG, String.format("mobile: %s sig=%d typ=%d",
                         (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
@@ -401,8 +416,8 @@
             }
         }
 
-        public void setIconTint(int tint) {
-            setTint(mMobile, tint);
+        public void setIconTint(int tint, float darkIntensity) {
+            applyDarkIntensity(darkIntensity, mMobile, mMobileDark);
             setTint(mMobileType, tint);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPanel.java
deleted file mode 100644
index 272c321..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPanel.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-public interface StatusBarPanel {
-    public boolean isInContentArea(int x, int y);
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 3b8fccc..9d892f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -69,7 +69,7 @@
         @Override
         public void onAnimationEnd(Animator animation) {
             mSwipeAnimator = null;
-            setSwipingInProgress(false);
+            mSwipingInProgress = false;
         }
     };
     private Runnable mAnimationEndRunnable = new Runnable() {
@@ -83,9 +83,9 @@
         mContext = context;
         mCallback = callback;
         initIcons();
-        updateIcon(mLeftIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false, false);
-        updateIcon(mCenterIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false, false);
-        updateIcon(mRightIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false, false);
+        updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false);
+        updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false);
+        updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false);
         initDimens();
     }
 
@@ -117,14 +117,17 @@
     }
 
     public boolean onTouchEvent(MotionEvent event) {
-        if (mMotionCancelled && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+        int action = event.getActionMasked();
+        if (mMotionCancelled && action != MotionEvent.ACTION_DOWN
+                && action != MotionEvent.ACTION_UP
+                && action != MotionEvent.ACTION_CANCEL) {
             return false;
         }
         final float y = event.getY();
         final float x = event.getX();
 
         boolean isUp = false;
-        switch (event.getActionMasked()) {
+        switch (action) {
             case MotionEvent.ACTION_DOWN:
                 if (mSwipingInProgress) {
                     cancelAnimation();
@@ -152,7 +155,8 @@
                     mInitialTouchY = y;
                     mInitialTouchX = x;
                     mTranslationOnDown = mTranslation;
-                    setSwipingInProgress(true);
+                    mSwipingInProgress = true;
+                    mCallback.onSwipingStarted(w < -mTouchSlop);
                 }
                 if (mSwipingInProgress) {
                     setTranslation(mTranslationOnDown + x - mInitialTouchX, false, false);
@@ -179,13 +183,6 @@
         }
     }
 
-    private void setSwipingInProgress(boolean inProgress) {
-        mSwipingInProgress = inProgress;
-        if (inProgress) {
-            mCallback.onSwipingStarted();
-        }
-    }
-
     private boolean rightSwipePossible() {
         return mRightIcon.getVisibility() == View.VISIBLE;
     }
@@ -323,6 +320,9 @@
         }
         animator.start();
         mSwipeAnimator = animator;
+        if (snapBack) {
+            mCallback.onSwipingAborted();
+        }
     }
 
     private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable) {
@@ -344,22 +344,23 @@
             float alpha = absTranslation / getMinTranslationAmount();
 
             // We interpolate the alpha of the other icons to 0
-            float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
-            fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
-
-            // We interpolate the alpha of the targetView to 1
-            alpha = fadeOutAlpha + alpha;
+            float fadeOutAlpha = 1.0f - alpha;
+            fadeOutAlpha = Math.min(1.0f, Math.max(0.0f, fadeOutAlpha));
 
             boolean animateIcons = isReset && animateReset;
             float radius = getRadiusFromTranslation(absTranslation);
             boolean slowAnimation = isReset && isBelowFalsingThreshold();
             if (!isReset) {
-                updateIcon(targetView, radius, alpha, false, false);
+                updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(),
+                        false, false);
             } else {
-                updateIcon(targetView, 0.0f, fadeOutAlpha, animateIcons, slowAnimation);
+                updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(),
+                        animateIcons, slowAnimation);
             }
-            updateIcon(otherView, 0.0f, fadeOutAlpha, animateIcons, slowAnimation);
-            updateIcon(mCenterIcon, 0.0f, fadeOutAlpha, animateIcons, slowAnimation);
+            updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(),
+                    animateIcons, slowAnimation);
+            updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(),
+                    animateIcons, slowAnimation);
 
             mTranslation = translation;
         }
@@ -369,15 +370,14 @@
         float alpha = newRadius / mMinBackgroundRadius;
 
         // We interpolate the alpha of the other icons to 0
-        float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
+        float fadeOutAlpha =  1.0f - alpha;
         fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
 
         // We interpolate the alpha of the targetView to 1
-        alpha = fadeOutAlpha + alpha;
         KeyguardAffordanceView otherView = targetView == mRightIcon ? mLeftIcon : mRightIcon;
-        updateIconAlpha(targetView, alpha, false);
-        updateIconAlpha(otherView, fadeOutAlpha, false);
-        updateIconAlpha(mCenterIcon, fadeOutAlpha, false);
+        updateIconAlpha(targetView, alpha + fadeOutAlpha * targetView.getRestingAlpha(), false);
+        updateIconAlpha(otherView, fadeOutAlpha * otherView.getRestingAlpha(), false);
+        updateIconAlpha(mCenterIcon, fadeOutAlpha * mCenterIcon.getRestingAlpha(), false);
     }
 
     private float getTranslationFromRadius(float circleSize) {
@@ -404,14 +404,14 @@
     }
 
     private void updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate) {
-        float scale = getScale(alpha);
+        float scale = getScale(alpha, view);
         alpha = Math.min(1.0f, alpha);
         view.setImageAlpha(alpha, animate);
         view.setImageScale(scale, animate);
     }
 
-    private float getScale(float alpha) {
-        float scale = alpha / SWIPE_RESTING_ALPHA_AMOUNT * 0.2f +
+    private float getScale(float alpha, KeyguardAffordanceView icon) {
+        float scale = alpha / icon.getRestingAlpha() * 0.2f +
                 KeyguardAffordanceView.MIN_ICON_SCALE_AMOUNT;
         return Math.min(scale, KeyguardAffordanceView.MAX_ICON_SCALE_AMOUNT);
     }
@@ -451,7 +451,11 @@
             mSwipeAnimator.cancel();
         }
         setTranslation(0.0f, true, animate);
-        setSwipingInProgress(false);
+        mMotionCancelled = true;
+        if (mSwipingInProgress) {
+            mCallback.onSwipingAborted();
+        }
+        mSwipingInProgress = false;
     }
 
     public interface Callback {
@@ -470,7 +474,9 @@
 
         float getPageWidth();
 
-        void onSwipingStarted();
+        void onSwipingStarted(boolean isRightwardMotion);
+
+        void onSwipingAborted();
 
         KeyguardAffordanceView getLeftIcon();
 
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 a247c8e..410a7e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -25,13 +25,16 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.InsetDrawable;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.Vibrator;
 import android.provider.MediaStore;
+import android.provider.Settings;
 import android.telecom.TelecomManager;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -78,6 +81,9 @@
     private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
     private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
     private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
+    private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300;
+    private static final long[] FP_ERROR_VIBRATE_PATTERN = new long[] {0, 30, 100, 30};
+    private static final long[] FP_SUCCESS_VIBRATE_PATTERN = new long[] {0, 30};
 
     private KeyguardAffordanceView mCameraImageView;
     private KeyguardAffordanceView mPhoneImageView;
@@ -100,6 +106,8 @@
     private final TrustDrawable mTrustDrawable;
     private final Interpolator mLinearOutSlowInInterpolator;
     private int mLastUnlockIconRes = 0;
+    private boolean mPrewarmSent;
+    private boolean mTransientFpError;
 
     public KeyguardBottomAreaView(Context context) {
         this(context, null);
@@ -335,12 +343,47 @@
         mLockPatternUtils.requireCredentialEntry(mLockPatternUtils.getCurrentUser());
     }
 
-    public void launchCamera() {
+    public void prewarmCamera() {
         Intent intent = getCameraIntent();
+        String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
+                mLockPatternUtils.getCurrentUser());
+        if (targetPackage != null) {
+            Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM);
+            prewarm.setPackage(targetPackage);
+            mPrewarmSent = true;
+            mContext.sendBroadcast(prewarm);
+        }
+    }
+
+    public void maybeCooldownCamera() {
+        if (!mPrewarmSent) {
+            return;
+        }
+        mPrewarmSent = false;
+        Intent intent = getCameraIntent();
+        String targetPackage = PreviewInflater.getTargetPackage(mContext, intent,
+                mLockPatternUtils.getCurrentUser());
+        if (targetPackage != null) {
+            Intent prewarm = new Intent(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN);
+            prewarm.setPackage(targetPackage);
+            mContext.sendBroadcast(prewarm);
+        }
+    }
+
+    public void launchCamera() {
+
+        // Reset prewarm state.
+        mPrewarmSent = false;
+        final Intent intent = getCameraIntent();
         boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
                 mContext, intent, mLockPatternUtils.getCurrentUser());
         if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+            AsyncTask.execute(new Runnable() {
+                @Override
+                public void run() {
+                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                }
+            });
         } else {
 
             // We need to delay starting the activity because ResolverActivity finishes itself if
@@ -395,28 +438,41 @@
             return;
         }
         // TODO: Real icon for facelock.
-        int iconRes = mUnlockMethodCache.isFaceUnlockRunning()
-                ? com.android.internal.R.drawable.ic_account_circle
+        boolean isFingerprintIcon =
+                KeyguardUpdateMonitor.getInstance(mContext).isFingerprintDetectionRunning();
+        boolean anyFingerprintIcon = isFingerprintIcon || mTransientFpError;
+        int iconRes = mTransientFpError ? R.drawable.ic_fingerprint_error
+                : isFingerprintIcon ? R.drawable.ic_fingerprint
+                : mUnlockMethodCache.isFaceUnlockRunning()
+                        ? com.android.internal.R.drawable.ic_account_circle
                 : mUnlockMethodCache.isCurrentlyInsecure() ? R.drawable.ic_lock_open_24dp
                 : R.drawable.ic_lock_24dp;
+
         if (mLastUnlockIconRes != iconRes) {
             Drawable icon = mContext.getDrawable(iconRes);
             int iconHeight = getResources().getDimensionPixelSize(
                     R.dimen.keyguard_affordance_icon_height);
             int iconWidth = getResources().getDimensionPixelSize(
                     R.dimen.keyguard_affordance_icon_width);
-            if (icon.getIntrinsicHeight() != iconHeight || icon.getIntrinsicWidth() != iconWidth) {
+            if (!anyFingerprintIcon && (icon.getIntrinsicHeight() != iconHeight
+                    || icon.getIntrinsicWidth() != iconWidth)) {
                 icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
             }
             mLockIcon.setImageDrawable(icon);
+            mLockIcon.setPaddingRelative(0, 0, 0, anyFingerprintIcon
+                    ? getResources().getDimensionPixelSize(
+                            R.dimen.fingerprint_icon_additional_padding)
+                    : 0);
+            mLockIcon.setRestingAlpha(
+                    anyFingerprintIcon ? 1f : KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT);
         }
-        boolean trustManaged = mUnlockMethodCache.isTrustManaged();
+
+        // Hide trust circle when fingerprint is running.
+        boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
         mTrustDrawable.setTrustManaged(trustManaged);
         updateLockIconClickability();
     }
 
-
-
     public KeyguardAffordanceView getPhoneView() {
         return mPhoneImageView;
     }
@@ -494,6 +550,14 @@
                 .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
     }
 
+    private void vibrateFingerprintError() {
+        mContext.getSystemService(Vibrator.class).vibrate(FP_ERROR_VIBRATE_PATTERN, -1);
+    }
+
+    private void vibrateFingerprintSuccess() {
+        mContext.getSystemService(Vibrator.class).vibrate(FP_SUCCESS_VIBRATE_PATTERN, -1);
+    }
+
     private final BroadcastReceiver mDevicePolicyReceiver = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             post(new Runnable() {
@@ -505,6 +569,15 @@
         }
     };
 
+    private final Runnable mTransientFpErrorClearRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mTransientFpError = false;
+            mIndicationController.hideTransientIndication();
+            updateLockIcon();
+        }
+    };
+
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
         @Override
@@ -526,6 +599,33 @@
         public void onKeyguardVisibilityChanged(boolean showing) {
             updateLockIcon();
         }
+
+        @Override
+        public void onFingerprintAuthenticated(int userId) {
+            vibrateFingerprintSuccess();
+        }
+
+        @Override
+        public void onFingerprintRunningStateChanged(boolean running) {
+            updateLockIcon();
+        }
+
+        @Override
+        public void onFingerprintHelp(int msgId, String helpString) {
+            vibrateFingerprintError();
+            mTransientFpError = true;
+            mIndicationController.showTransientIndication(helpString,
+                    getResources().getColor(R.color.system_warning_color, null));
+            removeCallbacks(mTransientFpErrorClearRunnable);
+            postDelayed(mTransientFpErrorClearRunnable, TRANSIENT_FP_ERROR_TIMEOUT);
+            updateLockIcon();
+        }
+
+        @Override
+        public void onFingerprintError(int msgId, String errString) {
+            // TODO: Go to bouncer if this is "too many attempts" (lockout) error.
+            Log.i(TAG, "FP Error: " + errString);
+        }
     };
 
     public void setKeyguardIndicationController(
@@ -533,7 +633,6 @@
         mIndicationController = keyguardIndicationController;
     }
 
-
     /**
      * A wrapper around another Drawable that overrides the intrinsic size.
      */
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 12ff399..c62ad66 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -50,6 +50,8 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.DelegateViewHelper;
 import com.android.systemui.statusbar.policy.DeadZone;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -195,7 +197,7 @@
         mDelegateHelper.setDelegateView(view);
     }
 
-    public void setBar(BaseStatusBar phoneStatusBar) {
+    public void setBar(PhoneStatusBar phoneStatusBar) {
         mTaskSwitchHelper.setBar(phoneStatusBar);
         mDelegateHelper.setBar(phoneStatusBar);
     }
@@ -261,8 +263,8 @@
         return mCurrentView.findViewById(R.id.back);
     }
 
-    public View getHomeButton() {
-        return mCurrentView.findViewById(R.id.home);
+    public KeyButtonView getHomeButton() {
+        return (KeyButtonView) mCurrentView.findViewById(R.id.home);
     }
 
     public View getImeSwitchButton() {
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 195da46..02b6c19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1505,7 +1505,7 @@
                 lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
                         mFastOutLinearInterpolator);
             } else if (!active && mUnlockIconActive && mTracking) {
-                lockIcon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT, true,
+                lockIcon.setImageAlpha(lockIcon.getRestingAlpha(), true /* animate */,
                         150, mFastOutLinearInterpolator, null);
                 lockIcon.setImageScale(1.0f, true, 150,
                         mFastOutLinearInterpolator);
@@ -1796,8 +1796,8 @@
                 mFastOutSlowInInterpolator, new Runnable() {
                     @Override
                     public void run() {
-                        icon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT,
-                                true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
+                        icon.setImageAlpha(icon.getRestingAlpha(),
+                                true /* animate */, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
                                 mFastOutSlowInInterpolator, null);
                     }
                 });
@@ -1809,14 +1809,24 @@
     }
 
     @Override
-    public void onSwipingStarted() {
-        mSecureCameraLaunchManager.onSwipingStarted();
+    public void onSwipingStarted(boolean isRightwardMotion) {
+        boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? isRightwardMotion
+                : !isRightwardMotion;
+        if (!start) {
+            mSecureCameraLaunchManager.onSwipingStarted();
+            mKeyguardBottomArea.prewarmCamera();
+        }
         requestDisallowInterceptTouchEvent(true);
         mOnlyAffordanceInThisMotion = true;
         mQsTracking = false;
     }
 
     @Override
+    public void onSwipingAborted() {
+        mKeyguardBottomArea.maybeCooldownCamera();
+    }
+
+    @Override
     public KeyguardAffordanceView getLeftIcon() {
         return getLayoutDirection() == LAYOUT_DIRECTION_RTL
                 ? mKeyguardBottomArea.getCameraView()
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 3efaaff..c6e1be9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -187,11 +187,11 @@
                 (fullyOpenedPanel!=null)?" fullyOpened":"", fullyClosed?" fullyClosed":"");
     }
 
-    public void collapseAllPanels(boolean animate) {
+    public void collapseAllPanels(boolean animate, boolean delayed) {
         boolean waiting = false;
         for (PanelView pv : mPanels) {
             if (animate && !pv.isFullyCollapsed()) {
-                pv.collapse(true /* delayed */);
+                pv.collapse(delayed);
                 waiting = true;
             } else {
                 pv.resetViews();
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 2c389fb..7c199cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -49,7 +49,6 @@
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
@@ -114,6 +113,7 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
@@ -121,6 +121,7 @@
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.assist.AssistGestureManager;
 import com.android.systemui.statusbar.BackDropView;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
@@ -225,8 +226,6 @@
     /** Allow some time inbetween the long press for back and recents. */
     private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
 
-    private int mLightModeIconColor;
-
     PhoneStatusBarPolicy mIconPolicy;
 
     // These are no longer handled by the policy, because we need custom strategies for them
@@ -323,6 +322,8 @@
     private int mNavigationIconHints = 0;
     private HandlerThread mHandlerThread;
 
+    private AssistGestureManager mAssistGestureManager;
+
     // ensure quick settings is disabled until the current user makes it through the setup wizard
     private boolean mUserSetup = false;
     private ContentObserver mUserSetupObserver = new ContentObserver(new Handler()) {
@@ -535,7 +536,6 @@
         updateDisplaySize();
         mScrimSrcModeEnabled = mContext.getResources().getBoolean(
                 R.bool.config_status_bar_scrim_behind_use_src);
-        mLightModeIconColor = mContext.getColor(R.color.light_mode_icon_color);
 
         super.start(); // calls createAndAddWindows()
 
@@ -642,8 +642,8 @@
                         new NavigationBarView.OnVerticalChangedListener() {
                     @Override
                     public void onVerticalChanged(boolean isVertical) {
-                        if (mSearchPanelView != null) {
-                            mSearchPanelView.setHorizontal(isVertical);
+                        if (mAssistGestureManager != null) {
+                            mAssistGestureManager.onConfigurationChanged();
                         }
                         mNotificationPanel.setQsScrimEnabled(!isVertical);
                     }
@@ -834,6 +834,8 @@
         mBroadcastReceiver.onReceive(mContext,
                 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
 
+        mAssistGestureManager = new AssistGestureManager(this, context);
+
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -953,60 +955,9 @@
         return mStatusBarWindow;
     }
 
-    @Override
-    protected WindowManager.LayoutParams getSearchLayoutParams(LayoutParams layoutParams) {
-        boolean opaque = false;
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
-                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
-                | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
-                (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
-        if (ActivityManager.isHighEndGfx()) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        }
-        lp.gravity = Gravity.BOTTOM | Gravity.START;
-        lp.setTitle("SearchPanel");
-        lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
-        | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
-        return lp;
-    }
-
-    @Override
-    protected void updateSearchPanel() {
-        super.updateSearchPanel();
-        if (mNavigationBarView != null) {
-            mNavigationBarView.setDelegateView(mSearchPanelView);
-        }
-    }
-
-    @Override
-    public void showSearchPanel() {
-        super.showSearchPanel();
-        mHandler.removeCallbacks(mShowSearchPanel);
-
-        // we want to freeze the sysui state wherever it is
-        mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility);
-
-        if (mNavigationBarView != null) {
-            WindowManager.LayoutParams lp =
-                (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
-            lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            mWindowManager.updateViewLayout(mNavigationBarView, lp);
-        }
-    }
-
-    @Override
-    public void hideSearchPanel() {
-        super.hideSearchPanel();
-        if (mNavigationBarView != null) {
-            WindowManager.LayoutParams lp =
-                (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
-            lp.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            mWindowManager.updateViewLayout(mNavigationBarView, lp);
-        }
+    public void invokeAssistGesture(boolean vibrate) {
+        mHandler.removeCallbacks(mInvokeAssist);
+        mAssistGestureManager.onGestureInvoked(vibrate);
     }
 
     public int getStatusBarHeight() {
@@ -1036,30 +987,33 @@
     };
 
     private int mShowSearchHoldoff = 0;
-    private Runnable mShowSearchPanel = new Runnable() {
+    private Runnable mInvokeAssist = new Runnable() {
         public void run() {
-            showSearchPanel();
+            invokeAssistGesture(true /* vibrate */);
             awakenDreams();
+            if (mNavigationBarView != null) {
+                mNavigationBarView.getHomeButton().abortCurrentGesture();
+            }
         }
     };
 
     View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
         public boolean onTouch(View v, MotionEvent event) {
-            switch(event.getAction()) {
+            switch (event.getAction()) {
                 case MotionEvent.ACTION_DOWN:
-                if (!shouldDisableNavbarGestures()) {
-                    mHandler.removeCallbacks(mShowSearchPanel);
-                    mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
-                }
-            break;
+                    if (!shouldDisableNavbarGestures()) {
+                        mHandler.removeCallbacks(mInvokeAssist);
+                        mHandler.postDelayed(mInvokeAssist, mShowSearchHoldoff);
+                    }
+                    break;
 
-            case MotionEvent.ACTION_UP:
-            case MotionEvent.ACTION_CANCEL:
-                mHandler.removeCallbacks(mShowSearchPanel);
-                awakenDreams();
-            break;
-        }
-        return false;
+                case MotionEvent.ACTION_UP:
+                case MotionEvent.ACTION_CANCEL:
+                    mHandler.removeCallbacks(mInvokeAssist);
+                    awakenDreams();
+                    break;
+            }
+            return false;
         }
     };
 
@@ -1083,7 +1037,7 @@
         mNavigationBarView.getBackButton().setLongClickable(true);
         mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
-        updateSearchPanel();
+        mAssistGestureManager.onConfigurationChanged();
     }
 
     // For small-screen devices (read: phones) that lack hardware navigation buttons
@@ -2038,10 +1992,14 @@
     }
 
     public void animateCollapsePanels(int flags) {
-        animateCollapsePanels(flags, false /* force */);
+        animateCollapsePanels(flags, false /* force */, false /* delayed */);
     }
 
     public void animateCollapsePanels(int flags, boolean force) {
+        animateCollapsePanels(flags, force, false /* delayed*/);
+    }
+
+    public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
         if (!force &&
                 (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) {
             runPostCollapseRunnables();
@@ -2060,17 +2018,12 @@
             }
         }
 
-        if ((flags & CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL) == 0) {
-            mHandler.removeMessages(MSG_CLOSE_SEARCH_PANEL);
-            mHandler.sendEmptyMessage(MSG_CLOSE_SEARCH_PANEL);
-        }
-
         if (mStatusBarWindow != null) {
             // release focus immediately to kick off focus change transition
             mStatusBarWindowManager.setStatusBarFocusable(false);
 
             mStatusBarWindow.cancelExpandHelper();
-            mStatusBarView.collapseAllPanels(true);
+            mStatusBarView.collapseAllPanels(true /* animate */, delayed);
         }
     }
 
@@ -2113,7 +2066,7 @@
 
     public void animateCollapseQuickSettings() {
         if (mState == StatusBarState.SHADE) {
-            mStatusBarView.collapseAllPanels(true);
+            mStatusBarView.collapseAllPanels(true, false /* delayed */);
         }
     }
 
@@ -2126,7 +2079,7 @@
         }
 
         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
-        mStatusBarView.collapseAllPanels(/*animate=*/ false);
+        mStatusBarView.collapseAllPanels(/*animate=*/ false, false /* delayed*/);
 
         // reset things to their proper state
         mStackScroller.setVisibility(View.VISIBLE);
@@ -2220,7 +2173,7 @@
             mStatusBarWindowState = state;
             if (DEBUG_WINDOW_STATE) Log.d(TAG, "Status bar " + windowStateToString(state));
             if (!showing && mState == StatusBarState.SHADE) {
-                mStatusBarView.collapseAllPanels(false);
+                mStatusBarView.collapseAllPanels(false /* animate */, false /* delayed */);
             }
         }
         if (mNavigationBarView != null
@@ -2324,9 +2277,7 @@
                 boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
                 boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
 
-                mIconController.setIconTint(
-                        (allowLight && light) ? mLightModeIconColor : Color.WHITE);
-
+                mIconController.setIconsDark(allowLight && light);
             }
             // restore the recents bit
             if (wasRecentsVisible) {
@@ -2627,8 +2578,7 @@
         }
 
         pw.println("SharedPreferences:");
-        for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(),
-                Context.MODE_PRIVATE).getAll().entrySet()) {
+        for (Map.Entry<String, ?> entry : Prefs.getAll(mContext).entrySet()) {
             pw.print("  "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue());
         }
     }
@@ -2697,8 +2647,8 @@
                     }
                 });
                 if (dismissShade) {
-                    animateCollapsePanels(
-                            CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
+                    animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
+                            true /* delayed*/);
                 }
                 return true;
             }
@@ -2989,7 +2939,7 @@
     };
 
     @Override
-    protected boolean shouldDisableNavbarGestures() {
+    public boolean shouldDisableNavbarGestures() {
         return !isDeviceProvisioned()
                 || mExpandedVisible
                 || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
@@ -3058,6 +3008,7 @@
             mHandlerThread = null;
         }
         mContext.unregisterReceiver(mBroadcastReceiver);
+        mAssistGestureManager.destroy();
     }
 
     private boolean mDemoModeAllowed;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 2236aae..ac93ced 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -199,7 +199,7 @@
         int volumeIconId = 0;
         String volumeDescription = null;
 
-        if (DndTile.isVisible(mContext)) {
+        if (DndTile.isVisible(mContext) || DndTile.isCombinedIcon(mContext)) {
             zenVisible = mZen != Global.ZEN_MODE_OFF;
             zenIconId = R.drawable.stat_sys_dnd;
             zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
@@ -218,7 +218,7 @@
             volumeVisible = true;
             volumeIconId = R.drawable.stat_sys_ringer_silent;
             volumeDescription = mContext.getString(R.string.accessibility_ringer_silent);
-        } else if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS &&
+        } else if (mZen != Global.ZEN_MODE_NO_INTERRUPTIONS && mZen != Global.ZEN_MODE_ALARMS &&
                 audioManager.getRingerModeInternal() == AudioManager.RINGER_MODE_VIBRATE) {
             volumeVisible = true;
             volumeIconId = R.drawable.stat_sys_ringer_vibrate;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index c49f620..45da297 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -16,11 +16,11 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.ArgbEvaluator;
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
-import android.graphics.PorterDuff;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
@@ -74,12 +74,16 @@
     private int mIconHPadding;
 
     private int mIconTint = Color.WHITE;
+    private float mDarkIntensity;
 
     private boolean mTransitionPending;
     private boolean mTintChangePending;
-    private int mPendingIconTint;
+    private float mPendingDarkIntensity;
     private ValueAnimator mTintAnimator;
 
+    private int mDarkModeIconColorSingleTone;
+    private int mLightModeIconColorSingleTone;
+
     private final Handler mHandler;
     private boolean mTransitionDeferring;
     private long mTransitionDeferringStartTime;
@@ -111,6 +115,8 @@
                 android.R.interpolator.linear_out_slow_in);
         mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
                 android.R.interpolator.fast_out_slow_in);
+        mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone);
+        mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone);
         mHandler = new Handler();
         updateResources();
     }
@@ -296,30 +302,31 @@
         }
     }
 
-    public void setIconTint(int tint) {
+    public void setIconsDark(boolean dark) {
         if (mTransitionPending) {
-            deferIconTintChange(tint);
+            deferIconTintChange(dark ? 1.0f : 0.0f);
         } else if (mTransitionDeferring) {
-            animateIconTint(tint,
+            animateIconTint(dark ? 1.0f : 0.0f,
                     Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
                     mTransitionDeferringDuration);
         } else {
-            animateIconTint(tint, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+            animateIconTint(dark ? 1.0f : 0.0f, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
         }
     }
 
-    private void animateIconTint(int targetTint, long delay, long duration) {
+    private void animateIconTint(float targetDarkIntensity, long delay,
+            long duration) {
         if (mTintAnimator != null) {
             mTintAnimator.cancel();
         }
-        if (mIconTint == targetTint) {
+        if (mDarkIntensity == targetDarkIntensity) {
             return;
         }
-        mTintAnimator = ValueAnimator.ofArgb(mIconTint, targetTint);
+        mTintAnimator = ValueAnimator.ofFloat(mDarkIntensity, targetDarkIntensity);
         mTintAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                setIconTintInternal((Integer) animation.getAnimatedValue());
+                setIconTintInternal((Float) animation.getAnimatedValue());
             }
         });
         mTintAnimator.setDuration(duration);
@@ -327,17 +334,20 @@
         mTintAnimator.setInterpolator(mFastOutSlowIn);
         mTintAnimator.start();
     }
-    private void setIconTintInternal(int tint) {
-        mIconTint = tint;
+
+    private void setIconTintInternal(float darkIntensity) {
+        mDarkIntensity = darkIntensity;
+        mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
+                mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone);
         applyIconTint();
     }
 
-    private void deferIconTintChange(int tint) {
-        if (mTintChangePending && tint == mPendingIconTint) {
+    private void deferIconTintChange(float darkIntensity) {
+        if (mTintChangePending && darkIntensity == mPendingDarkIntensity) {
             return;
         }
         mTintChangePending = true;
-        mPendingIconTint = tint;
+        mPendingDarkIntensity = darkIntensity;
     }
 
     private void applyIconTint() {
@@ -345,9 +355,9 @@
             StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
             v.setImageTintList(ColorStateList.valueOf(mIconTint));
         }
-        mSignalCluster.setIconTint(mIconTint);
+        mSignalCluster.setIconTint(mIconTint, mDarkIntensity);
         mMoreIcon.setImageTintList(ColorStateList.valueOf(mIconTint));
-        mBatteryMeterView.setIconTint(mIconTint);
+        mBatteryMeterView.setDarkIntensity(mDarkIntensity);
         mClock.setTextColor(mIconTint);
         applyNotificationIconsTint();
     }
@@ -358,7 +368,6 @@
             boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
             boolean colorize = !isPreL || isGrayscale(v);
             if (colorize) {
-                v.setImageTintMode(PorterDuff.Mode.SRC_ATOP);
                 v.setImageTintList(ColorStateList.valueOf(mIconTint));
             }
         }
@@ -381,7 +390,7 @@
     public void appTransitionCancelled() {
         if (mTransitionPending && mTintChangePending) {
             mTintChangePending = false;
-            animateIconTint(mPendingIconTint, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+            animateIconTint(mPendingDarkIntensity, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
         }
         mTransitionPending = false;
     }
@@ -389,7 +398,7 @@
     public void appTransitionStarting(long startTime, long duration) {
         if (mTransitionPending && mTintChangePending) {
             mTintChangePending = false;
-            animateIconTint(mPendingIconTint,
+            animateIconTint(mPendingDarkIntensity,
                     Math.max(0, startTime - SystemClock.uptimeMillis()),
                     duration);
 
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 a18daed..6bc51fa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -48,6 +48,7 @@
     private int mTouchSlop;
     private boolean mSupportsLongpress = true;
     private AudioManager mAudioManager;
+    private boolean mGestureAborted;
 
     private final Runnable mCheckLongPress = new Runnable() {
         public void run() {
@@ -126,10 +127,15 @@
     public boolean onTouchEvent(MotionEvent ev) {
         final int action = ev.getAction();
         int x, y;
+        if (action == MotionEvent.ACTION_DOWN) {
+            mGestureAborted = false;
+        }
+        if (mGestureAborted) {
+            return false;
+        }
 
         switch (action) {
             case MotionEvent.ACTION_DOWN:
-                //Log.d("KeyButtonView", "press");
                 mDownTime = SystemClock.uptimeMillis();
                 setPressed(true);
                 if (mCode != 0) {
@@ -203,6 +209,11 @@
         InputManager.getInstance().injectInputEvent(ev,
                 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
     }
+
+    public void abortCurrentGesture() {
+        setPressed(false);
+        mGestureAborted = true;
+    }
 }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
index 34068fd..0dce82f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -106,15 +107,28 @@
 
     public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent,
             int currentUserId) {
+        return getTargetPackage(ctx, intent, currentUserId) == null;
+    }
+
+    /**
+     * @return the target package of the intent it resolves to a specific package or {@code null} if
+     *         it resolved to the resolver activity
+     */
+    public static String getTargetPackage(Context ctx, Intent intent,
+            int currentUserId) {
         PackageManager packageManager = ctx.getPackageManager();
         final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser(
                 intent, PackageManager.MATCH_DEFAULT_ONLY, currentUserId);
         if (appList.size() == 0) {
-            return false;
+            return null;
         }
         ResolveInfo resolved = packageManager.resolveActivityAsUser(intent,
                 PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_META_DATA, currentUserId);
-        return wouldLaunchResolverActivity(resolved, appList);
+        if (resolved == null || wouldLaunchResolverActivity(resolved, appList)) {
+            return null;
+        } else {
+            return resolved.activityInfo.packageName;
+        }
     }
 
     private static boolean wouldLaunchResolverActivity(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 0e21457..67cc788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -17,16 +17,19 @@
 package com.android.systemui.statusbar.policy;
 
 import android.content.ComponentName;
+import android.net.Uri;
 import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ZenRule;
 
 public interface ZenModeController {
     void addCallback(Callback callback);
     void removeCallback(Callback callback);
-    void setZen(int zen);
+    void setZen(int zen, Uri conditionId, String reason);
     int getZen();
     void requestConditions(boolean request);
-    void setExitCondition(Condition exitCondition);
-    Condition getExitCondition();
+    ZenRule getManualRule();
+    ZenModeConfig getConfig();
     long getNextAlarm();
     void setUserId(int userId);
     boolean isZenAvailable();
@@ -35,10 +38,11 @@
 
     public static class Callback {
         public void onZenChanged(int zen) {}
-        public void onExitConditionChanged(Condition exitCondition) {}
         public void onConditionsChanged(Condition[] conditions) {}
         public void onNextAlarmChanged() {}
         public void onZenAvailableChanged(boolean available) {}
         public void onEffectsSupressorChanged() {}
+        public void onManualRuleChanged(ZenRule rule) {}
+        public void onConfigChanged(ZenModeConfig config) {}
     }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index bea0c86..830a197 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -33,6 +33,7 @@
 import android.service.notification.Condition;
 import android.service.notification.IConditionListener;
 import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ZenRule;
 import android.util.Log;
 import android.util.Slog;
 
@@ -40,6 +41,7 @@
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
+import java.util.Objects;
 
 /** Platform implementation of the zen mode controller. **/
 public class ZenModeControllerImpl implements ZenModeController {
@@ -58,6 +60,7 @@
     private int mUserId;
     private boolean mRequesting;
     private boolean mRegistered;
+    private ZenModeConfig mConfig;
 
     public ZenModeControllerImpl(Context context, Handler handler) {
         mContext = context;
@@ -70,12 +73,13 @@
         mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) {
             @Override
             protected void handleValueChanged(int value) {
-                fireExitConditionChanged();
+                updateZenModeConfig();
             }
         };
+        mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        mConfig = mNoMan.getZenModeConfig();
         mModeSetting.setListening(true);
         mConfigSetting.setListening(true);
-        mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mSetupObserver = new SetupObserver(handler);
         mSetupObserver.register();
@@ -97,8 +101,8 @@
     }
 
     @Override
-    public void setZen(int zen) {
-        mModeSetting.setValue(zen);
+    public void setZen(int zen, Uri conditionId, String reason) {
+        mNoMan.setZenMode(zen, conditionId, reason);
     }
 
     @Override
@@ -116,13 +120,13 @@
     }
 
     @Override
-    public void setExitCondition(Condition exitCondition) {
-        mNoMan.setZenModeCondition(exitCondition);
+    public ZenRule getManualRule() {
+        return mConfig == null ? null : mConfig.manualRule;
     }
 
     @Override
-    public Condition getExitCondition() {
-        return mNoMan.getZenModeCondition();
+    public ZenModeConfig getConfig() {
+        return mConfig;
     }
 
     @Override
@@ -185,11 +189,15 @@
         }
     }
 
-    private void fireExitConditionChanged() {
-        final Condition exitCondition = getExitCondition();
-        if (DEBUG) Slog.d(TAG, "exitCondition changed: " + exitCondition);
+    private void fireManualRuleChanged(ZenRule rule) {
         for (Callback cb : mCallbacks) {
-            cb.onExitConditionChanged(exitCondition);
+            cb.onManualRuleChanged(rule);
+        }
+    }
+
+    private void fireConfigChanged(ZenModeConfig config) {
+        for (Callback cb : mCallbacks) {
+            cb.onConfigChanged(config);
         }
     }
 
@@ -203,6 +211,17 @@
                 mConditions.values().toArray(new Condition[mConditions.values().size()]));
     }
 
+    private void updateZenModeConfig() {
+        final ZenModeConfig config = mNoMan.getZenModeConfig();
+        if (Objects.equals(config, mConfig)) return;
+        final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null;
+        mConfig = config;
+        fireConfigChanged(config);
+        final ZenRule newRule = config != null ? config.manualRule : null;
+        if (Objects.equals(oldRule, newRule)) return;
+        fireManualRuleChanged(newRule);
+    }
+
     private final IConditionListener mListener = new IConditionListener.Stub() {
         @Override
         public void onConditionsReceived(Condition[] conditions) {
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 d1e1b71..c272e48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -106,12 +106,6 @@
     }
 
     @Override
-    protected WindowManager.LayoutParams getSearchLayoutParams(
-            LayoutParams layoutParams) {
-        return null;
-    }
-
-    @Override
     protected void setAreThereNotifications() {
     }
 
@@ -120,7 +114,7 @@
     }
 
     @Override
-    protected boolean shouldDisableNavbarGestures() {
+    public boolean shouldDisableNavbarGestures() {
         return true;
     }
 
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/packages/SystemUI/src/com/android/systemui/volume/D.java
similarity index 80%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to packages/SystemUI/src/com/android/systemui/volume/D.java
index c9fd989..db7c853 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/packages/SystemUI/src/com/android/systemui/volume/D.java
@@ -13,7 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package com.android.systemui.volume;
+
+import android.util.Log;
+
+class D {
+    public static boolean BUG = Log.isLoggable("volume", Log.DEBUG);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
new file mode 100644
index 0000000..12dca94
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.provider.Settings.Global;
+import android.util.Log;
+
+import com.android.systemui.volume.VolumeDialogController.State;
+
+import java.util.Arrays;
+
+/**
+ *  Interesting events related to the volume.
+ */
+public class Events {
+    private static final String TAG = Util.logTag(Events.class);
+
+    public static final int EVENT_SHOW_DIALOG = 0;  // (reason|int) (keyguard|bool)
+    public static final int EVENT_DISMISS_DIALOG = 1; // (reason|int)
+    public static final int EVENT_ACTIVE_STREAM_CHANGED = 2; // (stream|int)
+    public static final int EVENT_EXPAND = 3; // (expand|bool)
+    public static final int EVENT_KEY = 4;
+    public static final int EVENT_COLLECTION_STARTED = 5;
+    public static final int EVENT_COLLECTION_STOPPED = 6;
+    public static final int EVENT_ICON_CLICK = 7; // (stream|int) (icon_state|int)
+    public static final int EVENT_SETTINGS_CLICK = 8;
+    public static final int EVENT_TOUCH_LEVEL_CHANGED = 9; // (stream|int) (level|int)
+    public static final int EVENT_LEVEL_CHANGED = 10; // (stream|int) (level|int)
+    public static final int EVENT_INTERNAL_RINGER_MODE_CHANGED = 11; // (mode|int)
+    public static final int EVENT_EXTERNAL_RINGER_MODE_CHANGED = 12; // (mode|int)
+    public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int)
+    public static final int EVENT_SUPPRESSOR_CHANGED = 14;  // (component|string) (name|string)
+    public static final int EVENT_MUTE_CHANGED = 15;  // (stream|int) (muted|bool)
+
+    private static final String[] EVENT_TAGS = {
+        "show_dialog",
+        "dismiss_dialog",
+        "active_stream_changed",
+        "expand",
+        "key",
+        "collection_started",
+        "collection_stopped",
+        "icon_click",
+        "settings_click",
+        "touch_level_changed",
+        "level_changed",
+        "internal_ringer_mode_changed",
+        "external_ringer_mode_changed",
+        "zen_mode_changed",
+        "suppressor_changed",
+        "mute_changed",
+    };
+
+    public static final int DISMISS_REASON_UNKNOWN = 0;
+    public static final int DISMISS_REASON_TOUCH_OUTSIDE = 1;
+    public static final int DISMISS_REASON_VOLUME_CONTROLLER = 2;
+    public static final int DISMISS_REASON_TIMEOUT = 3;
+    public static final int DISMISS_REASON_SCREEN_OFF = 4;
+    public static final int DISMISS_REASON_SETTINGS_CLICKED = 5;
+    public static final int DISMISS_REASON_DONE_CLICKED = 6;
+    public static final String[] DISMISS_REASONS = {
+        "unknown",
+        "touch_outside",
+        "volume_controller",
+        "timeout",
+        "screen_off",
+        "settings_clicked",
+        "done_clicked",
+    };
+
+    public static final int SHOW_REASON_UNKNOWN = 0;
+    public static final int SHOW_REASON_VOLUME_CHANGED = 1;
+    public static final int SHOW_REASON_REMOTE_VOLUME_CHANGED = 2;
+    public static final String[] SHOW_REASONS = {
+        "unknown",
+        "volume_changed",
+        "remote_volume_changed"
+    };
+
+    public static final int ICON_STATE_UNKNOWN = 0;
+    public static final int ICON_STATE_UNMUTE = 1;
+    public static final int ICON_STATE_MUTE = 2;
+    public static final int ICON_STATE_VIBRATE = 3;
+
+    public static Callback sCallback;
+
+    public static void writeEvent(int tag, Object... list) {
+        final long time = System.currentTimeMillis();
+        final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]);
+        if (list != null && list.length > 0) {
+            sb.append(" ");
+            switch (tag) {
+                case EVENT_SHOW_DIALOG:
+                    sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
+                    break;
+                case EVENT_EXPAND:
+                    sb.append(list[0]);
+                    break;
+                case EVENT_DISMISS_DIALOG:
+                    sb.append(DISMISS_REASONS[(Integer) list[0]]);
+                    break;
+                case EVENT_ACTIVE_STREAM_CHANGED:
+                    sb.append(AudioSystem.streamToString((Integer) list[0]));
+                    break;
+                case EVENT_ICON_CLICK:
+                    sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
+                            .append(iconStateToString((Integer) list[1]));
+                    break;
+                case EVENT_TOUCH_LEVEL_CHANGED:
+                case EVENT_LEVEL_CHANGED:
+                case EVENT_MUTE_CHANGED:
+                    sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ')
+                            .append(list[1]);
+                    break;
+                case EVENT_INTERNAL_RINGER_MODE_CHANGED:
+                case EVENT_EXTERNAL_RINGER_MODE_CHANGED:
+                    sb.append(ringerModeToString((Integer) list[0]));
+                    break;
+                case EVENT_ZEN_MODE_CHANGED:
+                    sb.append(zenModeToString((Integer) list[0]));
+                    break;
+                case EVENT_SUPPRESSOR_CHANGED:
+                    sb.append(list[0]).append(' ').append(list[1]);
+                    break;
+                default:
+                    sb.append(Arrays.asList(list));
+                    break;
+            }
+        }
+        Log.i(TAG, sb.toString());
+        if (sCallback != null) {
+            sCallback.writeEvent(time, tag, list);
+        }
+    }
+
+    public static void writeState(long time, State state) {
+        if (sCallback != null) {
+            sCallback.writeState(time, state);
+        }
+    }
+
+    private static String iconStateToString(int iconState) {
+        switch (iconState) {
+            case ICON_STATE_UNMUTE: return "unmute";
+            case ICON_STATE_MUTE: return "mute";
+            case ICON_STATE_VIBRATE: return "vibrate";
+            default: return "unknown_state_" + iconState;
+        }
+    }
+
+    private static String ringerModeToString(int ringerMode) {
+        switch (ringerMode) {
+            case AudioManager.RINGER_MODE_SILENT: return "silent";
+            case AudioManager.RINGER_MODE_VIBRATE: return "vibrate";
+            case AudioManager.RINGER_MODE_NORMAL: return "normal";
+            default: return "unknown";
+        }
+    }
+
+    private static String zenModeToString(int zenMode) {
+        switch (zenMode) {
+            case Global.ZEN_MODE_OFF: return "off";
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return "important_interruptions";
+            case Global.ZEN_MODE_ALARMS: return "alarms";
+            case Global.ZEN_MODE_NO_INTERRUPTIONS: return "no_interruptions";
+            default: return "unknown";
+        }
+    }
+
+    public interface Callback {
+        void writeEvent(long time, int tag, Object[] list);
+        void writeState(long time, State state);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java b/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java
new file mode 100644
index 0000000..712ea27
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.media.IRemoteVolumeController;
+import android.media.MediaMetadata;
+import android.media.session.ISessionController;
+import android.media.session.MediaController;
+import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.QueueItem;
+import android.media.session.MediaSession.Token;
+import android.media.session.MediaSessionManager;
+import android.media.session.MediaSessionManager.OnActiveSessionsChangedListener;
+import android.media.session.PlaybackState;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Convenience client for all media session updates.  Provides a callback interface for events
+ * related to remote media sessions.
+ */
+public class MediaSessions {
+    private static final String TAG = Util.logTag(MediaSessions.class);
+
+    private static final boolean USE_SERVICE_LABEL = false;
+
+    private final Context mContext;
+    private final H mHandler;
+    private final MediaSessionManager mMgr;
+    private final Map<Token, MediaControllerRecord> mRecords = new HashMap<>();
+    private final Callbacks mCallbacks;
+
+    private boolean mInit;
+
+    public MediaSessions(Context context, Looper looper, Callbacks callbacks) {
+        mContext = context;
+        mHandler = new H(looper);
+        mMgr = (MediaSessionManager) context.getSystemService(Context.MEDIA_SESSION_SERVICE);
+        mCallbacks = callbacks;
+    }
+
+    public void dump(PrintWriter writer) {
+        writer.println(getClass().getSimpleName() + " state:");
+        writer.print("  mInit: "); writer.println(mInit);
+        writer.print("  mRecords.size: "); writer.println(mRecords.size());
+        int i = 0;
+        for (MediaControllerRecord r : mRecords.values()) {
+            dump(++i, writer, r.controller);
+        }
+    }
+
+    public void init() {
+        if (D.BUG) Log.d(TAG, "init");
+        // will throw if no permission
+        mMgr.addOnActiveSessionsChangedListener(mSessionsListener, null, mHandler);
+        mInit = true;
+        postUpdateSessions();
+        mMgr.setRemoteVolumeController(mRvc);
+    }
+
+    protected void postUpdateSessions() {
+        if (!mInit) return;
+        mHandler.sendEmptyMessage(H.UPDATE_SESSIONS);
+    }
+
+    public void destroy() {
+        if (D.BUG) Log.d(TAG, "destroy");
+        mInit = false;
+        mMgr.removeOnActiveSessionsChangedListener(mSessionsListener);
+    }
+
+    public void setVolume(Token token, int level) {
+        final MediaControllerRecord r = mRecords.get(token);
+        if (r == null) {
+            Log.w(TAG, "setVolume: No record found for token " + token);
+            return;
+        }
+        if (D.BUG) Log.d(TAG, "Setting level to " + level);
+        r.controller.setVolumeTo(level, 0);
+    }
+
+    private void onRemoteVolumeChangedH(ISessionController session, int flags) {
+        final MediaController controller = new MediaController(mContext, session);
+        if (D.BUG) Log.d(TAG, "remoteVolumeChangedH " + controller.getPackageName() + " "
+                + Util.audioManagerFlagsToString(flags));
+        final Token token = controller.getSessionToken();
+        mCallbacks.onRemoteVolumeChanged(token, flags);
+    }
+
+    private void onUpdateRemoteControllerH(ISessionController session) {
+        final MediaController controller = session != null ? new MediaController(mContext, session)
+                : null;
+        final String pkg = controller != null ? controller.getPackageName() : null;
+        if (D.BUG) Log.d(TAG, "updateRemoteControllerH " + pkg);
+        // this may be our only indication that a remote session is changed, refresh
+        postUpdateSessions();
+    }
+
+    protected void onActiveSessionsUpdatedH(List<MediaController> controllers) {
+        if (D.BUG) Log.d(TAG, "onActiveSessionsUpdatedH n=" + controllers.size());
+        final Set<Token> toRemove = new HashSet<Token>(mRecords.keySet());
+        for (MediaController controller : controllers) {
+            final Token token = controller.getSessionToken();
+            final PlaybackInfo pi = controller.getPlaybackInfo();
+            toRemove.remove(token);
+            if (!mRecords.containsKey(token)) {
+                final MediaControllerRecord r = new MediaControllerRecord(controller);
+                r.name = getControllerName(controller);
+                mRecords.put(token, r);
+                controller.registerCallback(r, mHandler);
+            }
+            final MediaControllerRecord r = mRecords.get(token);
+            final boolean remote = isRemote(pi);
+            if (remote) {
+                updateRemoteH(token, r.name, pi);
+                r.sentRemote = true;
+            }
+        }
+        for (Token t : toRemove) {
+            final MediaControllerRecord r = mRecords.get(t);
+            r.controller.unregisterCallback(r);
+            mRecords.remove(t);
+            if (D.BUG) Log.d(TAG, "Removing " + r.name + " sentRemote=" + r.sentRemote);
+            if (r.sentRemote) {
+                mCallbacks.onRemoteRemoved(t);
+                r.sentRemote = false;
+            }
+        }
+    }
+
+    private static boolean isRemote(PlaybackInfo pi) {
+        return pi != null && pi.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE;
+    }
+
+    protected String getControllerName(MediaController controller) {
+        final PackageManager pm = mContext.getPackageManager();
+        final String pkg = controller.getPackageName();
+        try {
+            if (USE_SERVICE_LABEL) {
+                final List<ResolveInfo> ris = pm.queryIntentServices(
+                        new Intent("android.media.MediaRouteProviderService").setPackage(pkg), 0);
+                if (ris != null) {
+                    for (ResolveInfo ri : ris) {
+                        if (ri.serviceInfo == null) continue;
+                        if (pkg.equals(ri.serviceInfo.packageName)) {
+                            final String serviceLabel =
+                                    Objects.toString(ri.serviceInfo.loadLabel(pm), "").trim();
+                            if (serviceLabel.length() > 0) {
+                                return serviceLabel;
+                            }
+                        }
+                    }
+                }
+            }
+            final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+            final String appLabel = Objects.toString(ai.loadLabel(pm), "").trim();
+            if (appLabel.length() > 0) {
+                return appLabel;
+            }
+        } catch (NameNotFoundException e) { }
+        return pkg;
+    }
+
+    private void updateRemoteH(Token token, String name, PlaybackInfo pi) {
+        if (mCallbacks != null) {
+            mCallbacks.onRemoteUpdate(token, name, pi);
+        }
+    }
+
+    private static void dump(int n, PrintWriter writer, MediaController c) {
+        writer.println("  Controller " + n + ": " + c.getPackageName());
+        final Bundle extras = c.getExtras();
+        final long flags = c.getFlags();
+        final MediaMetadata mm = c.getMetadata();
+        final PlaybackInfo pi = c.getPlaybackInfo();
+        final PlaybackState playbackState = c.getPlaybackState();
+        final List<QueueItem> queue = c.getQueue();
+        final CharSequence queueTitle = c.getQueueTitle();
+        final int ratingType = c.getRatingType();
+        final PendingIntent sessionActivity = c.getSessionActivity();
+
+        writer.println("    PlaybackState: " + Util.playbackStateToString(playbackState));
+        writer.println("    PlaybackInfo: " + Util.playbackInfoToString(pi));
+        if (mm != null) {
+            writer.println("  MediaMetadata.desc=" + mm.getDescription());
+        }
+        writer.println("    RatingType: " + ratingType);
+        writer.println("    Flags: " + flags);
+        if (extras != null) {
+            writer.println("    Extras:");
+            for (String key : extras.keySet()) {
+                writer.println("      " + key + "=" + extras.get(key));
+            }
+        }
+        if (queueTitle != null) {
+            writer.println("    QueueTitle: " + queueTitle);
+        }
+        if (queue != null && !queue.isEmpty()) {
+            writer.println("    Queue:");
+            for (QueueItem qi : queue) {
+                writer.println("      " + qi);
+            }
+        }
+        if (pi != null) {
+            writer.println("    sessionActivity: " + sessionActivity);
+        }
+    }
+
+    public static void dumpMediaSessions(Context context) {
+        final MediaSessionManager mgr = (MediaSessionManager) context
+                .getSystemService(Context.MEDIA_SESSION_SERVICE);
+        try {
+            final List<MediaController> controllers = mgr.getActiveSessions(null);
+            final int N = controllers.size();
+            if (D.BUG) Log.d(TAG, N + " controllers");
+            for (int i = 0; i < N; i++) {
+                final StringWriter sw = new StringWriter();
+                final PrintWriter pw = new PrintWriter(sw, true);
+                dump(i + 1, pw, controllers.get(i));
+                if (D.BUG) Log.d(TAG, sw.toString());
+            }
+        } catch (SecurityException e) {
+            Log.w(TAG, "Not allowed to get sessions", e);
+        }
+    }
+
+    private final class MediaControllerRecord extends MediaController.Callback {
+        private final MediaController controller;
+
+        private boolean sentRemote;
+        private String name;
+
+        private MediaControllerRecord(MediaController controller) {
+            this.controller = controller;
+        }
+
+        private String cb(String method) {
+            return method + " " + controller.getPackageName() + " ";
+        }
+
+        @Override
+        public void onAudioInfoChanged(PlaybackInfo info) {
+            if (D.BUG) Log.d(TAG, cb("onAudioInfoChanged") + Util.playbackInfoToString(info)
+                    + " sentRemote=" + sentRemote);
+            final boolean remote = isRemote(info);
+            if (!remote && sentRemote) {
+                mCallbacks.onRemoteRemoved(controller.getSessionToken());
+                sentRemote = false;
+            } else if (remote) {
+                updateRemoteH(controller.getSessionToken(), name, info);
+                sentRemote = true;
+            }
+        }
+
+        @Override
+        public void onExtrasChanged(Bundle extras) {
+            if (D.BUG) Log.d(TAG, cb("onExtrasChanged") + extras);
+        }
+
+        @Override
+        public void onMetadataChanged(MediaMetadata metadata) {
+            if (D.BUG) Log.d(TAG, cb("onMetadataChanged") + Util.mediaMetadataToString(metadata));
+        }
+
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            if (D.BUG) Log.d(TAG, cb("onPlaybackStateChanged") + Util.playbackStateToString(state));
+        }
+
+        @Override
+        public void onQueueChanged(List<QueueItem> queue) {
+            if (D.BUG) Log.d(TAG, cb("onQueueChanged") + queue);
+        }
+
+        @Override
+        public void onQueueTitleChanged(CharSequence title) {
+            if (D.BUG) Log.d(TAG, cb("onQueueTitleChanged") + title);
+        }
+
+        @Override
+        public void onSessionDestroyed() {
+            if (D.BUG) Log.d(TAG, cb("onSessionDestroyed"));
+        }
+
+        @Override
+        public void onSessionEvent(String event, Bundle extras) {
+            if (D.BUG) Log.d(TAG, cb("onSessionEvent") + "event=" + event + " extras=" + extras);
+        }
+    }
+
+    private final OnActiveSessionsChangedListener mSessionsListener =
+            new OnActiveSessionsChangedListener() {
+        @Override
+        public void onActiveSessionsChanged(List<MediaController> controllers) {
+            onActiveSessionsUpdatedH(controllers);
+        }
+    };
+
+    private final IRemoteVolumeController mRvc = new IRemoteVolumeController.Stub() {
+        @Override
+        public void remoteVolumeChanged(ISessionController session, int flags)
+                throws RemoteException {
+            mHandler.obtainMessage(H.REMOTE_VOLUME_CHANGED, flags, 0, session).sendToTarget();
+        }
+
+        @Override
+        public void updateRemoteController(final ISessionController session)
+                throws RemoteException {
+            mHandler.obtainMessage(H.UPDATE_REMOTE_CONTROLLER, session).sendToTarget();
+        }
+    };
+
+    private final class H extends Handler {
+        private static final int UPDATE_SESSIONS = 1;
+        private static final int REMOTE_VOLUME_CHANGED = 2;
+        private static final int UPDATE_REMOTE_CONTROLLER = 3;
+
+        private H(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case UPDATE_SESSIONS:
+                    onActiveSessionsUpdatedH(mMgr.getActiveSessions(null));
+                    break;
+                case REMOTE_VOLUME_CHANGED:
+                    onRemoteVolumeChangedH((ISessionController) msg.obj, msg.arg1);
+                    break;
+                case UPDATE_REMOTE_CONTROLLER:
+                    onUpdateRemoteControllerH((ISessionController) msg.obj);
+                    break;
+            }
+        }
+    }
+
+    public interface Callbacks {
+        void onRemoteUpdate(Token token, String name, PlaybackInfo pi);
+        void onRemoteRemoved(Token t);
+        void onRemoteVolumeChanged(Token token, int flags);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Prefs.java b/packages/SystemUI/src/com/android/systemui/volume/Prefs.java
new file mode 100644
index 0000000..58bc9f4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/Prefs.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.preference.PreferenceManager;
+
+/**
+ *  Configuration for the volume dialog + related policy.
+ */
+public class Prefs {
+
+    public static final String PREF_ENABLE_PROTOTYPE = "pref_enable_prototype";  // not persistent
+    public static final String PREF_SHOW_ALARMS = "pref_show_alarms";
+    public static final String PREF_SHOW_SYSTEM = "pref_show_system";
+    public static final String PREF_SHOW_HEADERS = "pref_show_headers";
+    public static final String PREF_SHOW_FAKE_REMOTE_1 = "pref_show_fake_remote_1";
+    public static final String PREF_SHOW_FAKE_REMOTE_2 = "pref_show_fake_remote_2";
+    public static final String PREF_SHOW_FOOTER = "pref_show_footer";
+    public static final String PREF_ZEN_FOOTER = "pref_zen_footer";
+    public static final String PREF_ENABLE_AUTOMUTE = "pref_enable_automute";
+    public static final String PREF_ENABLE_SILENT_MODE = "pref_enable_silent_mode";
+    public static final String PREF_DEBUG_LOGGING = "pref_debug_logging";
+    public static final String PREF_SEND_LOGS = "pref_send_logs";
+    public static final String PREF_ADJUST_SYSTEM = "pref_adjust_system";
+    public static final String PREF_ADJUST_VOICE_CALLS = "pref_adjust_voice_calls";
+    public static final String PREF_ADJUST_BLUETOOTH_SCO = "pref_adjust_bluetooth_sco";
+    public static final String PREF_ADJUST_MEDIA = "pref_adjust_media";
+    public static final String PREF_ADJUST_ALARMS = "pref_adjust_alarms";
+    public static final String PREF_ADJUST_NOTIFICATION = "pref_adjust_notification";
+
+    public static final boolean DEFAULT_SHOW_HEADERS = true;
+    public static final boolean DEFAULT_SHOW_FOOTER = true;
+    public static final boolean DEFAULT_ENABLE_AUTOMUTE = true;
+    public static final boolean DEFAULT_ENABLE_SILENT_MODE = true;
+    public static final boolean DEFAULT_ZEN_FOOTER = true;
+
+    public static void unregisterCallbacks(Context c, OnSharedPreferenceChangeListener listener) {
+        prefs(c).unregisterOnSharedPreferenceChangeListener(listener);
+    }
+
+    public static void registerCallbacks(Context c, OnSharedPreferenceChangeListener listener) {
+        prefs(c).registerOnSharedPreferenceChangeListener(listener);
+    }
+
+    private static SharedPreferences prefs(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context);
+    }
+
+    public static boolean get(Context context, String key, boolean def) {
+        return prefs(context).getBoolean(key, def);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
new file mode 100644
index 0000000..04640a2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioManager;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.WindowManager;
+
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+abstract public class SafetyWarningDialog extends SystemUIDialog
+        implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
+
+    private static final String TAG = Util.logTag(SafetyWarningDialog.class);
+
+    private static final int KEY_CONFIRM_ALLOWED_AFTER = 1000; // milliseconds
+
+    private final Context mContext;
+    private final AudioManager mAudioManager;
+
+    private long mShowTime;
+    private boolean mNewVolumeUp;
+
+    public SafetyWarningDialog(Context context, AudioManager audioManager) {
+        super(context);
+        mContext = context;
+        mAudioManager = audioManager;
+
+        getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
+        setMessage(mContext.getString(com.android.internal.R.string.safe_media_volume_warning));
+        setButton(DialogInterface.BUTTON_POSITIVE,
+                mContext.getString(com.android.internal.R.string.yes), this);
+        setButton(DialogInterface.BUTTON_NEGATIVE,
+                mContext.getString(com.android.internal.R.string.no), (OnClickListener) null);
+        setOnDismissListener(this);
+
+        final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+        context.registerReceiver(mReceiver, filter);
+    }
+
+    abstract protected void cleanUp();
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && event.getRepeatCount() == 0) {
+            mNewVolumeUp = true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mNewVolumeUp
+                && (System.currentTimeMillis() - mShowTime) > KEY_CONFIRM_ALLOWED_AFTER) {
+            if (D.BUG) Log.d(TAG, "Confirmed warning via VOLUME_UP");
+            mAudioManager.disableSafeMediaVolume();
+            dismiss();
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public void onClick(DialogInterface dialog, int which) {
+        mAudioManager.disableSafeMediaVolume();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+        mShowTime = System.currentTimeMillis();
+    }
+
+    @Override
+    public void onDismiss(DialogInterface unused) {
+        mContext.unregisterReceiver(mReceiver);
+        cleanUp();
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                if (D.BUG) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
+                cancel();
+                cleanUp();
+            }
+        }
+    };
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
index 5f5b881..4f20ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SegmentedButtons.java
@@ -60,17 +60,14 @@
             final Object tag = c.getTag();
             final boolean selected = Objects.equals(mSelectedValue, tag);
             c.setSelected(selected);
-            c.getCompoundDrawables()[1].setTint(mContext.getColor(selected
-                    ? R.color.segmented_button_selected : R.color.segmented_button_unselected));
         }
         fireOnSelected();
     }
 
-    public void addButton(int labelResId, int iconResId, Object value) {
+    public void addButton(int labelResId, Object value) {
         final Button b = (Button) mInflater.inflate(R.layout.segmented_button, this, false);
         b.setTag(LABEL_RES_KEY, labelResId);
         b.setText(labelResId);
-        b.setCompoundDrawablesWithIntrinsicBounds(0, iconResId, 0, 0);
         final LayoutParams lp = (LayoutParams) b.getLayoutParams();
         if (getChildCount() == 0) {
             lp.leftMargin = lp.rightMargin = 0; // first button has no margin
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SpTexts.java b/packages/SystemUI/src/com/android/systemui/volume/SpTexts.java
new file mode 100644
index 0000000..d8e53db
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/SpTexts.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.ArrayMap;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
+import android.widget.TextView;
+
+/**
+ * Capture initial sp values for registered textviews, and update properly when configuration
+ * changes.
+ */
+public class SpTexts {
+
+    private final Context mContext;
+    private final ArrayMap<TextView, Integer> mTexts = new ArrayMap<>();
+
+    public SpTexts(Context context) {
+        mContext = context;
+    }
+
+    public int add(final TextView text) {
+        if (text == null) return 0;
+        final Resources res = mContext.getResources();
+        final float fontScale = res.getConfiguration().fontScale;
+        final float density = res.getDisplayMetrics().density;
+        final float px = text.getTextSize();
+        final int sp = (int)(px / fontScale / density);
+        mTexts.put(text, sp);
+        text.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
+            @Override
+            public void onViewDetachedFromWindow(View v) {
+            }
+
+            @Override
+            public void onViewAttachedToWindow(View v) {
+               setTextSizeH(text, sp);
+            }
+        });
+        return sp;
+    }
+
+    public void update() {
+        if (mTexts.isEmpty()) return;
+        mTexts.keyAt(0).post(mUpdateAll);
+    }
+
+    private void setTextSizeH(TextView text, int sp) {
+        text.setTextSize(TypedValue.COMPLEX_UNIT_SP, sp);
+    }
+
+    private final Runnable mUpdateAll = new Runnable() {
+        @Override
+        public void run() {
+            for (int i = 0; i < mTexts.size(); i++) {
+                setTextSizeH(mTexts.keyAt(i), mTexts.valueAt(i));
+            }
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Util.java b/packages/SystemUI/src/com/android/systemui/volume/Util.java
new file mode 100644
index 0000000..216a4da
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/Util.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.media.AudioManager;
+import android.media.MediaMetadata;
+import android.media.VolumeProvider;
+import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.PlaybackState;
+import android.view.View;
+import android.widget.TextView;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * Static helpers for the volume dialog.
+ */
+class Util {
+
+    // Note: currently not shown (only used in the text footer)
+    private static final SimpleDateFormat HMMAA = new SimpleDateFormat("h:mm aa", Locale.US);
+
+    private static int[] AUDIO_MANAGER_FLAGS = new int[] {
+        AudioManager.FLAG_SHOW_UI,
+        AudioManager.FLAG_VIBRATE,
+        AudioManager.FLAG_PLAY_SOUND,
+        AudioManager.FLAG_ALLOW_RINGER_MODES,
+        AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE,
+        AudioManager.FLAG_SHOW_VIBRATE_HINT,
+        AudioManager.FLAG_SHOW_SILENT_HINT,
+        AudioManager.FLAG_FROM_KEY,
+        AudioManager.FLAG_SHOW_UI_WARNINGS,
+    };
+
+    private static String[] AUDIO_MANAGER_FLAG_NAMES = new String[] {
+        "SHOW_UI",
+        "VIBRATE",
+        "PLAY_SOUND",
+        "ALLOW_RINGER_MODES",
+        "REMOVE_SOUND_AND_VIBRATE",
+        "SHOW_VIBRATE_HINT",
+        "SHOW_SILENT_HINT",
+        "FROM_KEY",
+        "SHOW_UI_WARNINGS",
+    };
+
+    public static String logTag(Class<?> c) {
+        final String tag = "vol." + c.getSimpleName();
+        return tag.length() < 23 ? tag : tag.substring(0, 23);
+    }
+
+    public static String ringerModeToString(int ringerMode) {
+        switch (ringerMode) {
+            case AudioManager.RINGER_MODE_SILENT: return "RINGER_MODE_SILENT";
+            case AudioManager.RINGER_MODE_VIBRATE: return "RINGER_MODE_VIBRATE";
+            case AudioManager.RINGER_MODE_NORMAL: return "RINGER_MODE_NORMAL";
+            default: return "RINGER_MODE_UNKNOWN_" + ringerMode;
+        }
+    }
+
+    public static String mediaMetadataToString(MediaMetadata metadata) {
+        return metadata.getDescription().toString();
+    }
+
+    public static String playbackInfoToString(PlaybackInfo info) {
+        if (info == null) return null;
+        final String type = playbackInfoTypeToString(info.getPlaybackType());
+        final String vc = volumeProviderControlToString(info.getVolumeControl());
+        return String.format("PlaybackInfo[vol=%s,max=%s,type=%s,vc=%s],atts=%s",
+                info.getCurrentVolume(), info.getMaxVolume(), type, vc, info.getAudioAttributes());
+    }
+
+    public static String playbackInfoTypeToString(int type) {
+        switch (type) {
+            case PlaybackInfo.PLAYBACK_TYPE_LOCAL: return "LOCAL";
+            case PlaybackInfo.PLAYBACK_TYPE_REMOTE: return "REMOTE";
+            default: return "UNKNOWN_" + type;
+        }
+    }
+
+    public static String playbackStateStateToString(int state) {
+        switch (state) {
+            case PlaybackState.STATE_NONE: return "STATE_NONE";
+            case PlaybackState.STATE_STOPPED: return "STATE_STOPPED";
+            case PlaybackState.STATE_PAUSED: return "STATE_PAUSED";
+            case PlaybackState.STATE_PLAYING: return "STATE_PLAYING";
+            default: return "UNKNOWN_" + state;
+        }
+    }
+
+    public static String volumeProviderControlToString(int control) {
+        switch (control) {
+            case VolumeProvider.VOLUME_CONTROL_ABSOLUTE: return "VOLUME_CONTROL_ABSOLUTE";
+            case VolumeProvider.VOLUME_CONTROL_FIXED: return "VOLUME_CONTROL_FIXED";
+            case VolumeProvider.VOLUME_CONTROL_RELATIVE: return "VOLUME_CONTROL_RELATIVE";
+            default: return "VOLUME_CONTROL_UNKNOWN_" + control;
+        }
+    }
+
+    public static String playbackStateToString(PlaybackState playbackState) {
+        if (playbackState == null) return null;
+        return playbackStateStateToString(playbackState.getState()) + " " + playbackState;
+    }
+
+    public static String audioManagerFlagsToString(int value) {
+        return bitFieldToString(value, AUDIO_MANAGER_FLAGS, AUDIO_MANAGER_FLAG_NAMES);
+    }
+
+    private static String bitFieldToString(int value, int[] values, String[] names) {
+        if (value == 0) return "";
+        final StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < values.length; i++) {
+            if ((value & values[i]) != 0) {
+                if (sb.length() > 0) sb.append(',');
+                sb.append(names[i]);
+            }
+            value &= ~values[i];
+        }
+        if (value != 0) {
+            if (sb.length() > 0) sb.append(',');
+            sb.append("UNKNOWN_").append(value);
+        }
+        return sb.toString();
+    }
+
+    public static String getShortTime(long millis) {
+        return HMMAA.format(new Date(millis));
+    }
+
+    public static void setText(TextView tv, CharSequence text) {
+        if (Objects.equals(tv.getText(), text)) return;
+        tv.setText(text);
+    }
+
+    public static final void setVisOrGone(View v, boolean vis) {
+        if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return;
+        v.setVisibility(vis ? View.VISIBLE : View.GONE);
+    }
+
+    public static final void setVisOrInvis(View v, boolean vis) {
+        if (v == null || (v.getVisibility() == View.VISIBLE) == vis) return;
+        v.setVisibility(vis ? View.VISIBLE : View.INVISIBLE);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
index e3f8f3d..1f0ee57 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeComponent.java
@@ -16,10 +16,18 @@
 
 package com.android.systemui.volume;
 
+import android.content.res.Configuration;
+
 import com.android.systemui.DemoMode;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 public interface VolumeComponent extends DemoMode {
     ZenModeController getZenController();
     void dismissNow();
+    void onConfigurationChanged(Configuration newConfig);
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+    void register();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
new file mode 100644
index 0000000..539fec8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -0,0 +1,1061 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
+import android.app.Dialog;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+import android.provider.Settings.Global;
+import android.service.notification.ZenModeConfig;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnLayoutChangeListener;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeDialogController.State;
+import com.android.systemui.volume.VolumeDialogController.StreamState;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Visual presentation of the volume dialog.
+ *
+ * A client of VolumeDialogController and its state model.
+ *
+ * Methods ending in "H" must be called on the (ui) handler.
+ */
+public class VolumeDialog {
+    private static final String TAG = Util.logTag(VolumeDialog.class);
+
+    private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
+    private static final int WAIT_FOR_RIPPLE = 200;
+    private static final int UPDATE_ANIMATION_DURATION = 80;
+
+    private final Context mContext;
+    private final H mHandler = new H();
+    private final VolumeDialogController mController;
+
+    private final CustomDialog mDialog;
+    private final ViewGroup mDialogView;
+    private final ViewGroup mDialogContentView;
+    private final ImageButton mExpandButton;
+    private final TextView mFootlineText;
+    private final Button mFootlineAction;
+    private final View mSettingsButton;
+    private final View mFooter;
+    private final List<VolumeRow> mRows = new ArrayList<VolumeRow>();
+    private final SpTexts mSpTexts;
+    private final SparseBooleanArray mDynamic = new SparseBooleanArray();
+    private final KeyguardManager mKeyguard;
+    private final int mExpandButtonAnimationDuration;
+    private final View mTextFooter;
+    private final ZenFooter mZenFooter;
+    private final LayoutTransition mLayoutTransition;
+    private final Object mSafetyWarningLock = new Object();
+
+    private boolean mShowing;
+    private boolean mExpanded;
+    private int mActiveStream;
+    private boolean mShowHeaders = Prefs.DEFAULT_SHOW_HEADERS;
+    private boolean mShowFooter = Prefs.DEFAULT_SHOW_FOOTER;
+    private boolean mShowZenFooter = Prefs.DEFAULT_ZEN_FOOTER;
+    private boolean mAutomute = Prefs.DEFAULT_ENABLE_AUTOMUTE;
+    private boolean mSilentMode = Prefs.DEFAULT_ENABLE_SILENT_MODE;
+    private State mState;
+    private int mExpandButtonRes;
+    private boolean mExpanding;
+    private SafetyWarningDialog mSafetyWarning;
+
+    public VolumeDialog(Context context, VolumeDialogController controller,
+            ZenModeController zenModeController) {
+        mContext = context;
+        mController = controller;
+        mSpTexts = new SpTexts(mContext);
+        mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
+
+        mDialog = new CustomDialog(mContext);
+
+        final Window window = mDialog.getWindow();
+        window.requestFeature(Window.FEATURE_NO_TITLE);
+        window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+        window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+        window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
+        mDialog.setCanceledOnTouchOutside(true);
+        final Resources res = mContext.getResources();
+        final WindowManager.LayoutParams lp = window.getAttributes();
+        lp.type = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.setTitle(VolumeDialog.class.getSimpleName());
+        lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
+        lp.windowAnimations = R.style.VolumeDialogAnimations;
+        lp.y = res.getDimensionPixelSize(R.dimen.volume_offset_top);
+        lp.gravity = Gravity.TOP;
+        window.setAttributes(lp);
+
+        mDialog.setContentView(R.layout.volume_dialog);
+        mDialogView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog);
+        mDialogContentView = (ViewGroup) mDialog.findViewById(R.id.volume_dialog_content);
+        mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
+        mExpandButton.setOnClickListener(mClickExpand);
+        updateWindowWidthH();
+        updateExpandButtonH();
+        mLayoutTransition = new LayoutTransition();
+        mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+        mLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING);
+        mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+        mDialogContentView.setLayoutTransition(mLayoutTransition);
+
+        addRow(AudioManager.STREAM_RING,
+                R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true);
+        addRow(AudioManager.STREAM_MUSIC,
+                R.drawable.ic_volume_media, R.drawable.ic_volume_media_mute, true);
+        addRow(AudioManager.STREAM_ALARM,
+                R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, false);
+        addRow(AudioManager.STREAM_VOICE_CALL,
+                R.drawable.ic_volume_voice, R.drawable.ic_volume_voice, false);
+        addRow(AudioManager.STREAM_BLUETOOTH_SCO,
+                R.drawable.ic_volume_bt_sco, R.drawable.ic_volume_bt_sco, false);
+        addRow(AudioManager.STREAM_SYSTEM,
+                R.drawable.ic_volume_system, R.drawable.ic_volume_system_mute, false);
+
+        mTextFooter = mDialog.findViewById(R.id.volume_text_footer);
+        mFootlineText = (TextView) mDialog.findViewById(R.id.volume_footline_text);
+        mSpTexts.add(mFootlineText);
+        mFootlineAction = (Button) mDialog.findViewById(R.id.volume_footline_action_button);
+        mSpTexts.add(mFootlineAction);
+        mFooter = mDialog.findViewById(R.id.volume_footer);
+        mSettingsButton = mDialog.findViewById(R.id.volume_settings_button);
+        mSettingsButton.setOnClickListener(mClickSettings);
+        mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
+        mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
+        mZenFooter.init(zenModeController, mZenFooterCallback);
+
+        controller.addCallback(mControllerCallbackH, mHandler);
+        controller.getState();
+    }
+
+    private void updateWindowWidthH() {
+        final ViewGroup.LayoutParams lp = mDialogView.getLayoutParams();
+        final DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+        if (D.BUG) Log.d(TAG, "updateWindowWidth dm.w=" + dm.widthPixels);
+        int w = dm.widthPixels;
+        final int max = mContext.getResources()
+                .getDimensionPixelSize(R.dimen.standard_notification_panel_width);
+        if (w > max) {
+            w = max;
+        }
+        w -= mContext.getResources().getDimensionPixelSize(R.dimen.notification_side_padding) * 2;
+        lp.width = w;
+        mDialogView.setLayoutParams(lp);
+    }
+
+    public void setStreamImportant(int stream, boolean important) {
+        mHandler.obtainMessage(H.SET_STREAM_IMPORTANT, stream, important ? 1 : 0).sendToTarget();
+    }
+
+    public void setShowHeaders(boolean showHeaders) {
+        if (showHeaders == mShowHeaders) return;
+        mShowHeaders = showHeaders;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    public void setShowFooter(boolean show) {
+        if (mShowFooter == show) return;
+        mShowFooter = show;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    public void setZenFooter(boolean zen) {
+        if (mShowZenFooter == zen) return;
+        mShowZenFooter = zen;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    public void setAutomute(boolean automute) {
+        if (mAutomute == automute) return;
+        mAutomute = automute;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    public void setSilentMode(boolean silentMode) {
+        if (mSilentMode == silentMode) return;
+        mSilentMode = silentMode;
+        mHandler.sendEmptyMessage(H.RECHECK_ALL);
+    }
+
+    private void addRow(int stream, int iconRes, int iconMuteRes, boolean important) {
+        final VolumeRow row = initRow(stream, iconRes, iconMuteRes, important);
+        if (!mRows.isEmpty()) {
+            final View v = new View(mContext);
+            final int h = mContext.getResources()
+                    .getDimensionPixelSize(R.dimen.volume_slider_interspacing);
+            final LinearLayout.LayoutParams lp =
+                    new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, h);
+            mDialogContentView.addView(v, mDialogContentView.getChildCount() - 1, lp);
+            row.space = v;
+        }
+        row.settingsButton.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                if (D.BUG) Log.d(TAG, "onLayoutChange"
+                        + " old=" + new Rect(oldLeft, oldTop, oldRight, oldBottom).toShortString()
+                        + " new=" + new Rect(left,top,right,bottom).toShortString());
+                if (oldLeft != left || oldTop != top) {
+                    for (int i = 0; i < mDialogContentView.getChildCount(); i++) {
+                        final View c = mDialogContentView.getChildAt(i);
+                        if (!c.isShown()) continue;
+                        if (c == row.view) {
+                            repositionExpandAnim(row);
+                        }
+                        return;
+                    }
+                }
+            }
+        });
+        // add new row just before the footer
+        mDialogContentView.addView(row.view, mDialogContentView.getChildCount() - 1);
+        mRows.add(row);
+    }
+
+    private boolean isAttached() {
+        return mDialogContentView != null && mDialogContentView.isAttachedToWindow();
+    }
+
+    private VolumeRow getActiveRow() {
+        for (VolumeRow row : mRows) {
+            if (row.stream == mActiveStream) {
+                return row;
+            }
+        }
+        return mRows.get(0);
+    }
+
+    private VolumeRow findRow(int stream) {
+        for (VolumeRow row : mRows) {
+            if (row.stream == stream) return row;
+        }
+        return null;
+    }
+
+    private void repositionExpandAnim(VolumeRow row) {
+        final int[] loc = new int[2];
+        row.settingsButton.getLocationInWindow(loc);
+        final MarginLayoutParams mlp = (MarginLayoutParams) mDialogView.getLayoutParams();
+        final int x = loc[0] - mlp.leftMargin;
+        final int y = loc[1] - mlp.topMargin;
+        if (D.BUG) Log.d(TAG, "repositionExpandAnim x=" + x + " y=" + y);
+        mExpandButton.setTranslationX(x);
+        mExpandButton.setTranslationY(y);
+    }
+
+    public void dump(PrintWriter writer) {
+        writer.println(VolumeDialog.class.getSimpleName() + " state:");
+        writer.print("  mShowing: "); writer.println(mShowing);
+        writer.print("  mExpanded: "); writer.println(mExpanded);
+        writer.print("  mExpanding: "); writer.println(mExpanding);
+        writer.print("  mActiveStream: "); writer.println(mActiveStream);
+        writer.print("  mDynamic: "); writer.println(mDynamic);
+        writer.print("  mShowHeaders: "); writer.println(mShowHeaders);
+        writer.print("  mShowFooter: "); writer.println(mShowFooter);
+        writer.print("  mAutomute: "); writer.println(mAutomute);
+        writer.print("  mSilentMode: "); writer.println(mSilentMode);
+    }
+
+    private static int getImpliedLevel(SeekBar seekBar, int progress) {
+        final int m = seekBar.getMax();
+        final int n = m / 100 - 1;
+        final int level = progress == 0 ? 0
+                : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
+        return level;
+    }
+
+    @SuppressLint("InflateParams")
+    private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) {
+        final VolumeRow row = new VolumeRow();
+        row.stream = stream;
+        row.iconRes = iconRes;
+        row.iconMuteRes = iconMuteRes;
+        row.important = important;
+        row.view = mDialog.getLayoutInflater().inflate(R.layout.volume_dialog_row, null);
+        row.view.setTag(row);
+        row.header = (TextView) row.view.findViewById(R.id.volume_row_header);
+        mSpTexts.add(row.header);
+        row.slider = (SeekBar) row.view.findViewById(R.id.volume_row_slider);
+        row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
+
+        // forward events above the slider into the slider
+        row.view.setOnTouchListener(new OnTouchListener() {
+            private final Rect mSliderHitRect = new Rect();
+            private boolean mDragging;
+
+            @SuppressLint("ClickableViewAccessibility")
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                row.slider.getHitRect(mSliderHitRect);
+                if (!mDragging && event.getActionMasked() == MotionEvent.ACTION_DOWN
+                        && event.getY() < mSliderHitRect.top) {
+                    mDragging = true;
+                }
+                if (mDragging) {
+                    event.offsetLocation(-mSliderHitRect.left, -mSliderHitRect.top);
+                    row.slider.dispatchTouchEvent(event);
+                    if (event.getActionMasked() == MotionEvent.ACTION_UP
+                            || event.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+                        mDragging = false;
+                    }
+                    return true;
+                }
+                return false;
+            }
+        });
+        row.icon = (ImageButton) row.view.findViewById(R.id.volume_row_icon);
+        row.icon.setImageResource(iconRes);
+        row.icon.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState);
+                mController.setActiveStream(row.stream);
+                if (row.stream == AudioManager.STREAM_RING) {
+                    final boolean hasVibrator = mController.hasVibrator();
+                    if (mState.ringerModeInternal == AudioManager.RINGER_MODE_NORMAL) {
+                        if (hasVibrator) {
+                            mController.setRingerMode(AudioManager.RINGER_MODE_VIBRATE, false);
+                        } else {
+                            final boolean wasZero = row.ss.level == 0;
+                            mController.setStreamVolume(stream, wasZero ? row.lastAudibleLevel : 0);
+                        }
+                    } else {
+                        mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+                        if (row.ss.level == 0) {
+                            mController.setStreamVolume(stream, 1);
+                        }
+                    }
+                } else {
+                    if (mAutomute && !row.ss.muteSupported) {
+                        final boolean vmute = row.ss.level == 0;
+                        mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0);
+                    } else {
+                        final boolean mute = !row.ss.muted;
+                        mController.setStreamMute(stream, mute);
+                        if (mAutomute) {
+                            if (!mute && row.ss.level == 0) {
+                                mController.setStreamVolume(stream, 1);
+                            }
+                        }
+                    }
+                }
+                row.userAttempt = 0;  // reset the grace period, slider should update immediately
+            }
+        });
+        row.settingsButton = (ImageButton) row.view.findViewById(R.id.volume_settings_button);
+        row.settingsButton.setOnClickListener(mClickSettings);
+        return row;
+    }
+
+    public void destroy() {
+        mController.removeCallback(mControllerCallbackH);
+    }
+
+    public void show(int reason) {
+        mHandler.obtainMessage(H.SHOW, reason, 0).sendToTarget();
+    }
+
+    public void dismiss(int reason) {
+        mHandler.obtainMessage(H.DISMISS, reason, 0).sendToTarget();
+    }
+
+    protected void onSettingsClickedH() {
+        // hook for subclasses
+    }
+
+    protected void onZenSettingsClickedH() {
+        // hook for subclasses
+    }
+
+    private void showH(int reason) {
+        mHandler.removeMessages(H.SHOW);
+        mHandler.removeMessages(H.DISMISS);
+        rescheduleTimeoutH();
+        if (mShowing) return;
+        mShowing = true;
+        mDialog.show();
+        Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
+        mController.notifyVisible(true);
+    }
+
+    protected void rescheduleTimeoutH() {
+        mHandler.removeMessages(H.DISMISS);
+        final int timeout = computeTimeoutH();
+        if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout);
+        mHandler.sendMessageDelayed(mHandler
+                .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
+        mController.userActivity();
+    }
+
+    private int computeTimeoutH() {
+        if (mZenFooter != null && mZenFooter.isFooterExpanded()) return 10000;
+        if (mSafetyWarning != null) return 5000;
+        if (mExpanded || mExpanding) return 5000;
+        if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
+        return 3000;
+    }
+
+    protected void dismissH(int reason) {
+        mHandler.removeMessages(H.DISMISS);
+        mHandler.removeMessages(H.SHOW);
+        if (!mShowing) return;
+        mShowing = false;
+        mDialog.dismiss();
+        Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason);
+        setExpandedH(false);
+        mController.notifyVisible(false);
+        synchronized (mSafetyWarningLock) {
+            if (mSafetyWarning != null) {
+                if (D.BUG) Log.d(TAG, "SafetyWarning dismissed");
+                mSafetyWarning.dismiss();
+            }
+        }
+    }
+
+    private void setExpandedH(boolean expanded) {
+        if (mExpanded == expanded) return;
+        mExpanded = expanded;
+        mExpanding = isAttached();
+        if (D.BUG) Log.d(TAG, "setExpandedH " + expanded);
+        updateRowsH();
+        if (mExpanding) {
+            final Drawable d = mExpandButton.getDrawable();
+            if (d instanceof AnimatedVectorDrawable) {
+                // workaround to reset drawable
+                final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) d.getConstantState()
+                        .newDrawable();
+                mExpandButton.setImageDrawable(avd);
+                avd.start();
+                mHandler.postDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        mExpanding = false;
+                        updateExpandButtonH();
+                        rescheduleTimeoutH();
+                    }
+                }, mExpandButtonAnimationDuration);
+            }
+        }
+        rescheduleTimeoutH();
+    }
+
+    private void updateExpandButtonH() {
+        mExpandButton.setClickable(!mExpanding);
+        if (mExpanding && isAttached()) return;
+        final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
+                : R.drawable.ic_volume_expand_animation;
+        if (res == mExpandButtonRes) return;
+        mExpandButtonRes = res;
+        mExpandButton.setImageResource(res);
+    }
+
+    private boolean isVisibleH(VolumeRow row, boolean isActive) {
+        return mExpanded && row.view.getVisibility() == View.VISIBLE
+                || (mExpanded && (row.important || isActive))
+                || !mExpanded && isActive;
+    }
+
+    private void updateRowsH() {
+        final VolumeRow activeRow = getActiveRow();
+        updateFooterH();
+        updateExpandButtonH();
+        final boolean footerVisible = mFooter.getVisibility() == View.VISIBLE;
+        if (!mShowing) {
+            trimObsoleteH();
+        }
+        // first, find the last visible row
+        VolumeRow lastVisible = null;
+        for (VolumeRow row : mRows) {
+            final boolean isActive = row == activeRow;
+            if (isVisibleH(row, isActive)) {
+                lastVisible = row;
+            }
+        }
+        // apply changes to all rows
+        for (VolumeRow row : mRows) {
+            final boolean isActive = row == activeRow;
+            final boolean visible = isVisibleH(row, isActive);
+            Util.setVisOrGone(row.view, visible);
+            Util.setVisOrGone(row.space, visible && mExpanded);
+            final int expandButtonRes = mExpanded ? R.drawable.ic_volume_settings : 0;
+            if (expandButtonRes != row.cachedExpandButtonRes) {
+                row.cachedExpandButtonRes = expandButtonRes;
+                if (expandButtonRes == 0) {
+                    row.settingsButton.setImageDrawable(null);
+                } else {
+                    row.settingsButton.setImageResource(expandButtonRes);
+                }
+            }
+            Util.setVisOrInvis(row.settingsButton,
+                     mExpanded && (!footerVisible && row == lastVisible));
+            row.header.setAlpha(mExpanded && isActive ? 1 : 0.5f);
+        }
+    }
+
+    private void trimObsoleteH() {
+        for (int i = mRows.size() -1; i >= 0; i--) {
+            final VolumeRow row = mRows.get(i);
+            if (row.ss == null || !row.ss.dynamic) continue;
+            if (!mDynamic.get(row.stream)) {
+                mRows.remove(i);
+                mDialogContentView.removeView(row.view);
+                mDialogContentView.removeView(row.space);
+            }
+        }
+    }
+
+    private void onStateChangedH(State state) {
+        mState = state;
+        mDynamic.clear();
+        // add any new dynamic rows
+        for (int i = 0; i < state.states.size(); i++) {
+            final int stream = state.states.keyAt(i);
+            final StreamState ss = state.states.valueAt(i);
+            if (!ss.dynamic) continue;
+            mDynamic.put(stream, true);
+            if (findRow(stream) == null) {
+                addRow(stream, R.drawable.ic_volume_remote, R.drawable.ic_volume_remote_mute, true);
+            }
+        }
+
+        if (mActiveStream != state.activeStream) {
+            mActiveStream = state.activeStream;
+            updateRowsH();
+            rescheduleTimeoutH();
+        }
+        for (VolumeRow row : mRows) {
+            updateVolumeRowH(row);
+        }
+        updateFooterH();
+    }
+
+    private void updateTextFooterH() {
+        final boolean zen = mState.zenMode != Global.ZEN_MODE_OFF;
+        final boolean wasVisible = mFooter.getVisibility() == View.VISIBLE;
+        Util.setVisOrGone(mTextFooter, mExpanded && mShowFooter && (zen || mShowing && wasVisible));
+        if (mTextFooter.getVisibility() == View.VISIBLE) {
+            String text = null;
+            String action = null;
+            if (mState.exitCondition != null) {
+                final long countdown = ZenModeConfig.tryParseCountdownConditionId(mState
+                        .exitCondition.id);
+                if (countdown != 0) {
+                    text = mContext.getString(R.string.volume_dnd_ends_at,
+                            Util.getShortTime(countdown));
+                    action = mContext.getString(R.string.volume_end_now);
+                }
+            }
+            if (text == null) {
+                text = mContext.getString(R.string.volume_dnd_is_on);
+            }
+            if (action == null) {
+                action = mContext.getString(R.string.volume_turn_off);
+            }
+            Util.setText(mFootlineText, text);
+            Util.setText(mFootlineAction, action);
+            mFootlineAction.setOnClickListener(mTurnOffDnd);
+        }
+        Util.setVisOrGone(mFootlineText, zen);
+        Util.setVisOrGone(mFootlineAction, zen);
+    }
+
+    private void updateFooterH() {
+        if (!mShowFooter) {
+            Util.setVisOrGone(mFooter, false);
+            return;
+        }
+        if (mShowZenFooter) {
+            Util.setVisOrGone(mTextFooter, false);
+            final boolean ringActive = mActiveStream == AudioManager.STREAM_RING;
+            Util.setVisOrGone(mZenFooter, mZenFooter.isZen() && ringActive
+                    || mShowing && (mExpanded || mZenFooter.getVisibility() == View.VISIBLE));
+            mZenFooter.update();
+        } else {
+            Util.setVisOrGone(mZenFooter, false);
+            updateTextFooterH();
+        }
+    }
+
+    private void updateVolumeRowH(VolumeRow row) {
+        if (mState == null) return;
+        final StreamState ss = mState.states.get(row.stream);
+        if (ss == null) return;
+        row.ss = ss;
+        if (ss.level > 0) {
+            row.lastAudibleLevel = ss.level;
+        }
+        final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
+        final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
+        final boolean isRingVibrate = isRingStream
+                && mState.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
+        final boolean isNoned = (isRingStream || isSystemStream)
+                && mState.zenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+        final boolean isLimited = isRingStream
+                && mState.zenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+
+        // update slider max
+        final int max = ss.levelMax * 100;
+        if (max != row.slider.getMax()) {
+            row.slider.setMax(max);
+        }
+
+        // update header visible
+        if (row.cachedShowHeaders != mShowHeaders) {
+            row.cachedShowHeaders = mShowHeaders;
+            Util.setVisOrGone(row.header, mShowHeaders);
+        }
+
+        // update header text
+        final String text;
+        if (isNoned) {
+            text = mContext.getString(R.string.volume_stream_muted_dnd, ss.name);
+        } else if (isRingVibrate && isLimited) {
+            text = mContext.getString(R.string.volume_stream_vibrate_dnd, ss.name);
+        } else if (isRingVibrate) {
+            text = mContext.getString(R.string.volume_stream_vibrate, ss.name);
+        } else if (ss.muted || mAutomute && ss.level == 0) {
+            text = mContext.getString(R.string.volume_stream_muted, ss.name);
+        } else if (isLimited) {
+            text = mContext.getString(R.string.volume_stream_limited_dnd, ss.name);
+        } else {
+            text = ss.name;
+        }
+        Util.setText(row.header, text);
+
+        // update icon
+        final boolean iconEnabled = mAutomute || ss.muteSupported;
+        row.icon.setEnabled(iconEnabled);
+        row.icon.setAlpha(iconEnabled ? 1 : 0.5f);
+        final int iconRes =
+                isRingVibrate ? R.drawable.ic_volume_ringer_vibrate
+                : ss.routedToBluetooth ?
+                        (ss.muted ? R.drawable.ic_volume_media_bt_mute
+                                : R.drawable.ic_volume_media_bt)
+                : mAutomute && ss.level == 0 ? row.iconMuteRes
+                : (ss.muted ? row.iconMuteRes : row.iconRes);
+        if (iconRes != row.cachedIconRes) {
+            if (row.cachedIconRes != 0 && isRingVibrate) {
+                mController.vibrate();
+            }
+            row.cachedIconRes = iconRes;
+            row.icon.setImageResource(iconRes);
+        }
+        row.iconState =
+                iconRes == R.drawable.ic_volume_ringer_vibrate ? Events.ICON_STATE_VIBRATE
+                : (iconRes == R.drawable.ic_volume_media_bt_mute || iconRes == row.iconMuteRes)
+                        ? Events.ICON_STATE_MUTE
+                : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes)
+                        ? Events.ICON_STATE_UNMUTE
+                : Events.ICON_STATE_UNKNOWN;
+
+        // update slider
+        updateVolumeRowSliderH(row);
+    }
+
+    private void updateVolumeRowSliderH(VolumeRow row) {
+        if (row.tracking) {
+            return;  // don't update if user is sliding
+        }
+        final int progress = row.slider.getProgress();
+        final int level = getImpliedLevel(row.slider, progress);
+        final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
+        final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
+                < USER_ATTEMPT_GRACE_PERIOD;
+        mHandler.removeMessages(H.RECHECK, row);
+        if (mShowing && rowVisible && inGracePeriod) {
+            if (D.BUG) Log.d(TAG, "inGracePeriod");
+            mHandler.sendMessageAtTime(mHandler.obtainMessage(H.RECHECK, row),
+                    row.userAttempt + USER_ATTEMPT_GRACE_PERIOD);
+            return;  // don't update if visible and in grace period
+        }
+        final int vlevel = row.ss.muted ? 0 : row.ss.level;
+        if (vlevel == level) {
+            if (mShowing && rowVisible) {
+                return;  // don't clamp if visible
+            }
+        }
+        final int newProgress = vlevel * 100;
+        if (progress != newProgress) {
+            if (mShowing && rowVisible) {
+                // animate!
+                if (row.anim != null && row.anim.isRunning()
+                        && row.animTargetProgress == newProgress) {
+                    return;  // already animating to the target progress
+                }
+                // start/update animation
+                if (row.anim == null) {
+                    row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
+                    row.anim.setInterpolator(new DecelerateInterpolator());
+                } else {
+                    row.anim.cancel();
+                    row.anim.setIntValues(progress, newProgress);
+                }
+                row.animTargetProgress = newProgress;
+                row.anim.setDuration(UPDATE_ANIMATION_DURATION);
+                row.anim.start();
+            } else {
+                // update slider directly to clamped value
+                if (row.anim != null) {
+                    row.anim.cancel();
+                }
+                row.slider.setProgress(newProgress);
+            }
+            if (mAutomute) {
+                if (vlevel == 0 && !row.ss.muted && row.stream == AudioManager.STREAM_MUSIC) {
+                    mController.setStreamMute(row.stream, true);
+                }
+            }
+        }
+    }
+
+    private void recheckH(VolumeRow row) {
+        if (row == null) {
+            if (D.BUG) Log.d(TAG, "recheckH ALL");
+            trimObsoleteH();
+            for (VolumeRow r : mRows) {
+                updateVolumeRowH(r);
+            }
+        } else {
+            if (D.BUG) Log.d(TAG, "recheckH " + row.stream);
+            updateVolumeRowH(row);
+        }
+    }
+
+    private void setStreamImportantH(int stream, boolean important) {
+        for (VolumeRow row : mRows) {
+            if (row.stream == stream) {
+                row.important = important;
+                return;
+            }
+        }
+    }
+
+    private void showSafetyWarningH(int flags) {
+        if ((flags & (AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_SHOW_UI_WARNINGS)) != 0
+                || mShowing) {
+            synchronized (mSafetyWarningLock) {
+                if (mSafetyWarning != null) {
+                    return;
+                }
+                mSafetyWarning = new SafetyWarningDialog(mContext, mController.getAudioManager()) {
+                    @Override
+                    protected void cleanUp() {
+                        synchronized (mSafetyWarningLock) {
+                            mSafetyWarning = null;
+                        }
+                        recheckH(null);
+                    }
+                };
+                mSafetyWarning.show();
+            }
+            recheckH(null);
+        }
+        rescheduleTimeoutH();
+    }
+
+    private final VolumeDialogController.Callbacks mControllerCallbackH
+            = new VolumeDialogController.Callbacks() {
+        @Override
+        public void onShowRequested(int reason) {
+            showH(reason);
+        }
+
+        @Override
+        public void onDismissRequested(int reason) {
+            dismissH(reason);
+        }
+
+        @Override
+        public void onScreenOff() {
+            dismissH(Events.DISMISS_REASON_SCREEN_OFF);
+        }
+
+        @Override
+        public void onStateChanged(State state) {
+            onStateChangedH(state);
+        }
+
+        @Override
+        public void onLayoutDirectionChanged(int layoutDirection) {
+            mDialogView.setLayoutDirection(layoutDirection);
+        }
+
+        @Override
+        public void onConfigurationChanged() {
+            updateWindowWidthH();
+            mSpTexts.update();
+        }
+
+        @Override
+        public void onShowVibrateHint() {
+            if (mSilentMode) {
+                mController.setRingerMode(AudioManager.RINGER_MODE_SILENT, false);
+            }
+        }
+
+        @Override
+        public void onShowSilentHint() {
+            if (mSilentMode) {
+                mController.setRingerMode(AudioManager.RINGER_MODE_NORMAL, false);
+            }
+        }
+
+        @Override
+        public void onShowSafetyWarning(int flags) {
+            showSafetyWarningH(flags);
+        }
+    };
+
+    private final OnClickListener mClickExpand = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (mExpanding) return;
+            final boolean newExpand = !mExpanded;
+            Events.writeEvent(Events.EVENT_EXPAND, v);
+            setExpandedH(newExpand);
+        }
+    };
+
+    private final OnClickListener mClickSettings = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mSettingsButton.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    Events.writeEvent(Events.EVENT_SETTINGS_CLICK);
+                    onSettingsClickedH();
+                }
+            }, WAIT_FOR_RIPPLE);
+        }
+    };
+
+    private final View.OnClickListener mTurnOffDnd = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mSettingsButton.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    mController.setZenMode(Global.ZEN_MODE_OFF);
+                }
+            }, WAIT_FOR_RIPPLE);
+        }
+    };
+
+    private final ZenFooter.Callback mZenFooterCallback = new ZenFooter.Callback() {
+        @Override
+        public void onFooterExpanded() {
+            mHandler.sendEmptyMessage(H.RESCHEDULE_TIMEOUT);
+        }
+
+        @Override
+        public void onSettingsClicked() {
+            dismiss(Events.DISMISS_REASON_SETTINGS_CLICKED);
+            onZenSettingsClickedH();
+        }
+
+        @Override
+        public void onDoneClicked() {
+            dismiss(Events.DISMISS_REASON_DONE_CLICKED);
+        }
+    };
+
+    private final class H extends Handler {
+        private static final int SHOW = 1;
+        private static final int DISMISS = 2;
+        private static final int RECHECK = 3;
+        private static final int RECHECK_ALL = 4;
+        private static final int SET_STREAM_IMPORTANT = 5;
+        private static final int RESCHEDULE_TIMEOUT = 6;
+
+        public H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case SHOW: showH(msg.arg1); break;
+                case DISMISS: dismissH(msg.arg1); break;
+                case RECHECK: recheckH((VolumeRow) msg.obj); break;
+                case RECHECK_ALL: recheckH(null); break;
+                case SET_STREAM_IMPORTANT: setStreamImportantH(msg.arg1, msg.arg2 != 0); break;
+                case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
+            }
+        }
+    }
+
+    private final class CustomDialog extends Dialog {
+        public CustomDialog(Context context) {
+            super(context);
+        }
+
+        @Override
+        public boolean dispatchTouchEvent(MotionEvent ev) {
+            rescheduleTimeoutH();
+            return super.dispatchTouchEvent(ev);
+        }
+
+        @Override
+        protected void onStop() {
+            super.onStop();
+            mHandler.sendEmptyMessage(H.RECHECK_ALL);
+        }
+
+        @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            if (isShowing()) {
+                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                    dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE);
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
+        private final VolumeRow mRow;
+
+        private VolumeSeekBarChangeListener(VolumeRow row) {
+            mRow = row;
+        }
+
+        @Override
+        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+            if (mRow.ss == null) return;
+            if (D.BUG) Log.d(TAG, AudioSystem.streamToString(mRow.stream)
+                    + " onProgressChanged " + progress + " fromUser=" + fromUser);
+            if (!fromUser) return;
+            if (mRow.ss.levelMin > 0) {
+                final int minProgress = mRow.ss.levelMin * 100;
+                if (progress < minProgress) {
+                    seekBar.setProgress(minProgress);
+                }
+            }
+            final int userLevel = getImpliedLevel(seekBar, progress);
+            if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
+                mRow.userAttempt = SystemClock.uptimeMillis();
+                if (mAutomute) {
+                    if (mRow.stream != AudioManager.STREAM_RING) {
+                        if (userLevel > 0 && mRow.ss.muted) {
+                            mController.setStreamMute(mRow.stream, false);
+                        }
+                        if (userLevel == 0 && mRow.ss.muteSupported && !mRow.ss.muted) {
+                            mController.setStreamMute(mRow.stream, true);
+                        }
+                    }
+                }
+                if (mRow.requestedLevel != userLevel) {
+                    mController.setStreamVolume(mRow.stream, userLevel);
+                    mRow.requestedLevel = userLevel;
+                    Events.writeEvent(Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream, userLevel);
+                }
+            }
+        }
+
+        @Override
+        public void onStartTrackingTouch(SeekBar seekBar) {
+            if (D.BUG) Log.d(TAG, "onStartTrackingTouch"+ " " + mRow.stream);
+            mController.setActiveStream(mRow.stream);
+            mRow.tracking = true;
+        }
+
+        @Override
+        public void onStopTrackingTouch(SeekBar seekBar) {
+            if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
+            mRow.tracking = false;
+            mRow.userAttempt = SystemClock.uptimeMillis();
+            int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
+            if (mRow.ss.level != userLevel) {
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
+                        USER_ATTEMPT_GRACE_PERIOD);
+            }
+        }
+    }
+
+    private static class VolumeRow {
+        private View view;
+        private View space;
+        private TextView header;
+        private ImageButton icon;
+        private SeekBar slider;
+        private ImageButton settingsButton;
+        private int stream;
+        private StreamState ss;
+        private long userAttempt;  // last user-driven slider change
+        private boolean tracking;  // tracking slider touch
+        private int requestedLevel;
+        private int iconRes;
+        private int iconMuteRes;
+        private boolean important;
+        private int cachedIconRes;
+        private int iconState;  // from Events
+        private boolean cachedShowHeaders = Prefs.DEFAULT_SHOW_HEADERS;
+        private int cachedExpandButtonRes;
+        private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
+        private int animTargetProgress;
+        private int lastAudibleLevel = 1;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
new file mode 100644
index 0000000..741e498
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.media.VolumePolicy;
+import android.os.Bundle;
+import android.os.Handler;
+
+import com.android.systemui.SystemUI;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Implementation of VolumeComponent backed by the new volume dialog.
+ */
+public class VolumeDialogComponent implements VolumeComponent {
+    private final SystemUI mSysui;
+    private final Context mContext;
+    private final VolumeDialogController mController;
+    private final ZenModeController mZenModeController;
+    private final VolumeDialog mDialog;
+
+    public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler,
+            ZenModeController zen) {
+        mSysui = sysui;
+        mContext = context;
+        mController = new VolumeDialogController(context, null) {
+            @Override
+            protected void onUserActivityW() {
+                sendUserActivity();
+            }
+        };
+        mZenModeController = zen;
+        mDialog = new VolumeDialog(context, mController, zen) {
+            @Override
+            protected void onZenSettingsClickedH() {
+                startZenSettings();
+            }
+        };
+        applyConfiguration();
+    }
+
+    private void sendUserActivity() {
+        final KeyguardViewMediator kvm = mSysui.getComponent(KeyguardViewMediator.class);
+        if (kvm != null) {
+            kvm.userActivity();
+        }
+    }
+
+    private void applyConfiguration() {
+        mDialog.setStreamImportant(AudioManager.STREAM_ALARM, true);
+        mDialog.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
+        mDialog.setShowHeaders(false);
+        mDialog.setShowFooter(true);
+        mDialog.setZenFooter(true);
+        mDialog.setAutomute(true);
+        mDialog.setSilentMode(false);
+        mController.setVolumePolicy(VolumePolicy.DEFAULT);
+        mController.showDndTile(false);
+    }
+
+    @Override
+    public ZenModeController getZenController() {
+        return mZenModeController;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        // noop
+    }
+
+    @Override
+    public void dismissNow() {
+        mController.dismiss();
+    }
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        // noop
+    }
+
+    @Override
+    public void register() {
+        mController.register();
+        DndTile.setCombinedIcon(mContext, true);
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mController.dump(fd, pw, args);
+        mDialog.dump(pw);
+    }
+
+    private void startZenSettings() {
+        mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
+                ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
new file mode 100644
index 0000000..5bc8c3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -0,0 +1,996 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.IVolumeController;
+import android.media.VolumePolicy;
+import android.media.session.MediaController.PlaybackInfo;
+import android.media.session.MediaSession.Token;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.Vibrator;
+import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.ZenModeConfig;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.systemui.R;
+import com.android.systemui.qs.tiles.DndTile;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ *  Source of truth for all state / events related to the volume dialog.  No presentation.
+ *
+ *  All work done on a dedicated background worker thread & associated worker.
+ *
+ *  Methods ending in "W" must be called on the worker thread.
+ */
+public class VolumeDialogController {
+    private static final String TAG = Util.logTag(VolumeDialogController.class);
+
+    private static final int DYNAMIC_STREAM_START_INDEX = 100;
+    private static final int VIBRATE_HINT_DURATION = 50;
+
+    private static final int[] STREAMS = {
+        AudioSystem.STREAM_ALARM,
+        AudioSystem.STREAM_BLUETOOTH_SCO,
+        AudioSystem.STREAM_DTMF,
+        AudioSystem.STREAM_MUSIC,
+        AudioSystem.STREAM_NOTIFICATION,
+        AudioSystem.STREAM_RING,
+        AudioSystem.STREAM_SYSTEM,
+        AudioSystem.STREAM_SYSTEM_ENFORCED,
+        AudioSystem.STREAM_TTS,
+        AudioSystem.STREAM_VOICE_CALL,
+    };
+
+    private final HandlerThread mWorkerThread;
+    private final W mWorker;
+    private final Context mContext;
+    private final AudioManager mAudio;
+    private final NotificationManager mNoMan;
+    private final ComponentName mComponent;
+    private final SettingObserver mObserver;
+    private final Receiver mReceiver = new Receiver();
+    private final MediaSessions mMediaSessions;
+    private final VC mVolumeController = new VC();
+    private final C mCallbacks = new C();
+    private final State mState = new State();
+    private final String[] mStreamTitles;
+    private final MediaSessionsCallbacks mMediaSessionsCallbacksW = new MediaSessionsCallbacks();
+    private final Vibrator mVibrator;
+    private final boolean mHasVibrator;
+
+    private boolean mEnabled;
+    private boolean mDestroyed;
+    private VolumePolicy mVolumePolicy = new VolumePolicy(true, true, false, 400);
+    private boolean mShowDndTile = false;
+
+    public VolumeDialogController(Context context, ComponentName component) {
+        mContext = context.getApplicationContext();
+        Events.writeEvent(Events.EVENT_COLLECTION_STARTED);
+        mComponent = component;
+        mWorkerThread = new HandlerThread(VolumeDialogController.class.getSimpleName());
+        mWorkerThread.start();
+        mWorker = new W(mWorkerThread.getLooper());
+        mMediaSessions = createMediaSessions(mContext, mWorkerThread.getLooper(),
+                mMediaSessionsCallbacksW);
+        mAudio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+        mNoMan = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+        mObserver = new SettingObserver(mWorker);
+        mObserver.init();
+        mReceiver.init();
+        mStreamTitles = mContext.getResources().getStringArray(R.array.volume_stream_titles);
+        mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+        mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
+    }
+
+    public AudioManager getAudioManager() {
+        return mAudio;
+    }
+
+    public void dismiss() {
+        mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
+    }
+
+    public void register() {
+        try {
+            mAudio.setVolumeController(mVolumeController);
+        } catch (SecurityException e) {
+            Log.w(TAG, "Unable to set the volume controller", e);
+            return;
+        }
+        setVolumePolicy(mVolumePolicy);
+        showDndTile(mShowDndTile);
+        try {
+            mMediaSessions.init();
+        } catch (SecurityException e) {
+            Log.w(TAG, "No access to media sessions", e);
+        }
+    }
+
+    public void setVolumePolicy(VolumePolicy policy) {
+        mVolumePolicy = policy;
+        try {
+            mAudio.setVolumePolicy(mVolumePolicy);
+        } catch (NoSuchMethodError e) {
+            Log.w(TAG, "No volume policy api");
+        }
+    }
+
+    protected MediaSessions createMediaSessions(Context context, Looper looper,
+            MediaSessions.Callbacks callbacks) {
+        return new MediaSessions(context, looper, callbacks);
+    }
+
+    public void destroy() {
+        if (D.BUG) Log.d(TAG, "destroy");
+        if (mDestroyed) return;
+        mDestroyed = true;
+        Events.writeEvent(Events.EVENT_COLLECTION_STOPPED);
+        mMediaSessions.destroy();
+        mObserver.destroy();
+        mReceiver.destroy();
+        mWorkerThread.quitSafely();
+    }
+
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(VolumeDialogController.class.getSimpleName() + " state:");
+        pw.print("  mEnabled: "); pw.println(mEnabled);
+        pw.print("  mDestroyed: "); pw.println(mDestroyed);
+        pw.print("  mVolumePolicy: "); pw.println(mVolumePolicy);
+        pw.print("  mEnabled: "); pw.println(mEnabled);
+        pw.print("  mShowDndTile: "); pw.println(mShowDndTile);
+        pw.print("  mHasVibrator: "); pw.println(mHasVibrator);
+        pw.print("  mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
+                .values());
+        pw.println();
+        mMediaSessions.dump(pw);
+    }
+
+    public void addCallback(Callbacks callback, Handler handler) {
+        mCallbacks.add(callback, handler);
+    }
+
+    public void removeCallback(Callbacks callback) {
+        mCallbacks.remove(callback);
+    }
+
+    public void getState() {
+        if (mDestroyed) return;
+        mWorker.sendEmptyMessage(W.GET_STATE);
+    }
+
+    public void notifyVisible(boolean visible) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.NOTIFY_VISIBLE, visible ? 1 : 0, 0).sendToTarget();
+    }
+
+    public void userActivity() {
+        if (mDestroyed) return;
+        mWorker.removeMessages(W.USER_ACTIVITY);
+        mWorker.sendEmptyMessage(W.USER_ACTIVITY);
+    }
+
+    public void setRingerMode(int value, boolean external) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.SET_RINGER_MODE, value, external ? 1 : 0).sendToTarget();
+    }
+
+    public void setZenMode(int value) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.SET_ZEN_MODE, value, 0).sendToTarget();
+    }
+
+    public void setExitCondition(Condition condition) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.SET_EXIT_CONDITION, condition).sendToTarget();
+    }
+
+    public void setStreamMute(int stream, boolean mute) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.SET_STREAM_MUTE, stream, mute ? 1 : 0).sendToTarget();
+    }
+
+    public void setStreamVolume(int stream, int level) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.SET_STREAM_VOLUME, stream, level).sendToTarget();
+    }
+
+    public void setActiveStream(int stream) {
+        if (mDestroyed) return;
+        mWorker.obtainMessage(W.SET_ACTIVE_STREAM, stream, 0).sendToTarget();
+    }
+
+    public void vibrate() {
+        if (mHasVibrator) {
+            mVibrator.vibrate(VIBRATE_HINT_DURATION);
+        }
+    }
+
+    public boolean hasVibrator() {
+        return mHasVibrator;
+    }
+
+    private void onNotifyVisibleW(boolean visible) {
+        if (mDestroyed) return;
+        mAudio.notifyVolumeControllerVisible(mVolumeController, visible);
+        if (!visible) {
+            if (updateActiveStreamW(-1)) {
+                mCallbacks.onStateChanged(mState);
+            }
+        }
+    }
+
+    protected void onUserActivityW() {
+        // hook for subclasses
+    }
+
+    private void onShowSafetyWarningW(int flags) {
+        mCallbacks.onShowSafetyWarning(flags);
+    }
+
+    private boolean checkRoutedToBluetoothW(int stream) {
+        boolean changed = false;
+        if (stream == AudioManager.STREAM_MUSIC) {
+            final boolean routedToBluetooth =
+                    (mAudio.getDevicesForStream(AudioManager.STREAM_MUSIC) &
+                            (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
+                            AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+                            AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0;
+            changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
+        }
+        return changed;
+    }
+
+    private void onVolumeChangedW(int stream, int flags) {
+        final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
+        final boolean fromKey = (flags & AudioManager.FLAG_FROM_KEY) != 0;
+        final boolean showVibrateHint = (flags & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0;
+        final boolean showSilentHint = (flags & AudioManager.FLAG_SHOW_SILENT_HINT) != 0;
+        boolean changed = false;
+        if (showUI) {
+            changed |= updateActiveStreamW(stream);
+        }
+        changed |= updateStreamLevelW(stream, mAudio.getLastAudibleStreamVolume(stream));
+        changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream);
+        if (changed) {
+            mCallbacks.onStateChanged(mState);
+        }
+        if (showUI) {
+            mCallbacks.onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
+        }
+        if (showVibrateHint) {
+            mCallbacks.onShowVibrateHint();
+        }
+        if (showSilentHint) {
+            mCallbacks.onShowSilentHint();
+        }
+        if (changed && fromKey) {
+            Events.writeEvent(Events.EVENT_KEY);
+        }
+    }
+
+    private boolean updateActiveStreamW(int activeStream) {
+        if (activeStream == mState.activeStream) return false;
+        mState.activeStream = activeStream;
+        Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream);
+        if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream);
+        final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1;
+        if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s);
+        mAudio.forceVolumeControlStream(s);
+        return true;
+    }
+
+    private StreamState streamStateW(int stream) {
+        StreamState ss = mState.states.get(stream);
+        if (ss == null) {
+            ss = new StreamState();
+            mState.states.put(stream, ss);
+        }
+        return ss;
+    }
+
+    private void onGetStateW() {
+        for (int stream : STREAMS) {
+            updateStreamLevelW(stream, mAudio.getLastAudibleStreamVolume(stream));
+            streamStateW(stream).levelMin = mAudio.getStreamMinVolume(stream);
+            streamStateW(stream).levelMax = mAudio.getStreamMaxVolume(stream);
+            updateStreamMuteW(stream, mAudio.isStreamMute(stream));
+            final StreamState ss = streamStateW(stream);
+            ss.muteSupported = mAudio.isStreamAffectedByMute(stream);
+            ss.name = mStreamTitles[stream];
+            checkRoutedToBluetoothW(stream);
+        }
+        updateRingerModeExternalW(mAudio.getRingerMode());
+        updateZenModeW();
+        updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
+        updateExitConditionW();
+        mCallbacks.onStateChanged(mState);
+    }
+
+    private boolean updateStreamRoutedToBluetoothW(int stream, boolean routedToBluetooth) {
+        final StreamState ss = streamStateW(stream);
+        if (ss.routedToBluetooth == routedToBluetooth) return false;
+        ss.routedToBluetooth = routedToBluetooth;
+        if (D.BUG) Log.d(TAG, "updateStreamRoutedToBluetoothW stream=" + stream
+                + " routedToBluetooth=" + routedToBluetooth);
+        return true;
+    }
+
+    private boolean updateStreamLevelW(int stream, int level) {
+        final StreamState ss = streamStateW(stream);
+        if (ss.level == level) return false;
+        ss.level = level;
+        if (isLogWorthy(stream)) {
+            Events.writeEvent(Events.EVENT_LEVEL_CHANGED, stream, level);
+        }
+        return true;
+    }
+
+    private static boolean isLogWorthy(int stream) {
+        switch (stream) {
+            case AudioSystem.STREAM_ALARM:
+            case AudioSystem.STREAM_BLUETOOTH_SCO:
+            case AudioSystem.STREAM_MUSIC:
+            case AudioSystem.STREAM_RING:
+            case AudioSystem.STREAM_SYSTEM:
+            case AudioSystem.STREAM_VOICE_CALL:
+                return true;
+        }
+        return false;
+    }
+
+    private boolean updateStreamMuteW(int stream, boolean muted) {
+        final StreamState ss = streamStateW(stream);
+        if (ss.muted == muted) return false;
+        ss.muted = muted;
+        if (isLogWorthy(stream)) {
+            Events.writeEvent(Events.EVENT_MUTE_CHANGED, stream, muted);
+        }
+        if (muted && isRinger(stream)) {
+            updateRingerModeInternalW(mAudio.getRingerModeInternal());
+        }
+        return true;
+    }
+
+    private static boolean isRinger(int stream) {
+        return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
+    }
+
+    private Condition getExitCondition() {
+        final ZenModeConfig config = mNoMan.getZenModeConfig();
+        return config == null ? null
+                : config.manualRule == null ? null
+                : config.manualRule.condition;
+    }
+
+    private boolean updateExitConditionW() {
+        final Condition exitCondition = getExitCondition();
+        if (Objects.equals(mState.exitCondition, exitCondition)) return false;
+        mState.exitCondition = exitCondition;
+        return true;
+    }
+
+    private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
+        if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
+        mState.effectsSuppressor = effectsSuppressor;
+        mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor);
+        Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor,
+                mState.effectsSuppressorName);
+        return true;
+    }
+
+    private static String getApplicationName(Context context, ComponentName component) {
+        if (component == null) return null;
+        final PackageManager pm = context.getPackageManager();
+        final String pkg = component.getPackageName();
+        try {
+            final ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+            final String rt = Objects.toString(ai.loadLabel(pm), "").trim();
+            if (rt.length() > 0) {
+                return rt;
+            }
+        } catch (NameNotFoundException e) {}
+        return pkg;
+    }
+
+    private boolean updateZenModeW() {
+        final int zen = Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF);
+        if (mState.zenMode == zen) return false;
+        mState.zenMode = zen;
+        Events.writeEvent(Events.EVENT_ZEN_MODE_CHANGED, zen);
+        return true;
+    }
+
+    private boolean updateRingerModeExternalW(int rm) {
+        if (rm == mState.ringerModeExternal) return false;
+        mState.ringerModeExternal = rm;
+        Events.writeEvent(Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm);
+        return true;
+    }
+
+    private boolean updateRingerModeInternalW(int rm) {
+        if (rm == mState.ringerModeInternal) return false;
+        mState.ringerModeInternal = rm;
+        Events.writeEvent(Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm);
+        return true;
+    }
+
+    private void onSetRingerModeW(int mode, boolean external) {
+        if (external) {
+            mAudio.setRingerMode(mode);
+        } else {
+            mAudio.setRingerModeInternal(mode);
+        }
+    }
+
+    private void onSetStreamMuteW(int stream, boolean mute) {
+        mAudio.adjustStreamVolume(stream, mute ? AudioManager.ADJUST_MUTE
+                : AudioManager.ADJUST_UNMUTE, 0);
+    }
+
+    private void onSetStreamVolumeW(int stream, int level) {
+        if (D.BUG) Log.d(TAG, "onSetStreamVolume " + stream + " level=" + level);
+        if (stream >= DYNAMIC_STREAM_START_INDEX) {
+            mMediaSessionsCallbacksW.setStreamVolume(stream, level);
+            return;
+        }
+        mAudio.setStreamVolume(stream, level, 0);
+    }
+
+    private void onSetActiveStreamW(int stream) {
+        boolean changed = updateActiveStreamW(stream);
+        if (changed) {
+            mCallbacks.onStateChanged(mState);
+        }
+    }
+
+    private void onSetExitConditionW(Condition condition) {
+        mNoMan.setZenMode(mState.zenMode, condition != null ? condition.id : null, TAG);
+    }
+
+    private void onSetZenModeW(int mode) {
+        if (D.BUG) Log.d(TAG, "onSetZenModeW " + mode);
+        mNoMan.setZenMode(mode, null, TAG);
+    }
+
+    private void onDismissRequestedW(int reason) {
+        mCallbacks.onDismissRequested(reason);
+    }
+
+    public void showDndTile(boolean visible) {
+        if (D.BUG) Log.d(TAG, "showDndTile");
+        DndTile.setVisible(mContext, visible);
+    }
+
+    private final class VC extends IVolumeController.Stub {
+        private final String TAG = VolumeDialogController.TAG + ".VC";
+
+        @Override
+        public void displaySafeVolumeWarning(int flags) throws RemoteException {
+            if (D.BUG) Log.d(TAG, "displaySafeVolumeWarning "
+                    + Util.audioManagerFlagsToString(flags));
+            if (mDestroyed) return;
+            mWorker.obtainMessage(W.SHOW_SAFETY_WARNING, flags, 0).sendToTarget();
+        }
+
+        @Override
+        public void volumeChanged(int streamType, int flags) throws RemoteException {
+            if (D.BUG) Log.d(TAG, "volumeChanged " + AudioSystem.streamToString(streamType)
+                    + " " + Util.audioManagerFlagsToString(flags));
+            if (mDestroyed) return;
+            mWorker.obtainMessage(W.VOLUME_CHANGED, streamType, flags).sendToTarget();
+        }
+
+        @Override
+        public void masterMuteChanged(int flags) throws RemoteException {
+            if (D.BUG) Log.d(TAG, "masterMuteChanged");
+        }
+
+        @Override
+        public void setLayoutDirection(int layoutDirection) throws RemoteException {
+            if (D.BUG) Log.d(TAG, "setLayoutDirection");
+            if (mDestroyed) return;
+            mWorker.obtainMessage(W.LAYOUT_DIRECTION_CHANGED, layoutDirection, 0).sendToTarget();
+        }
+
+        @Override
+        public void dismiss() throws RemoteException {
+            if (D.BUG) Log.d(TAG, "dismiss requested");
+            if (mDestroyed) return;
+            mWorker.obtainMessage(W.DISMISS_REQUESTED, Events.DISMISS_REASON_VOLUME_CONTROLLER, 0)
+                    .sendToTarget();
+            mWorker.sendEmptyMessage(W.DISMISS_REQUESTED);
+        }
+    }
+
+    private final class W extends Handler {
+        private static final int VOLUME_CHANGED = 1;
+        private static final int DISMISS_REQUESTED = 2;
+        private static final int GET_STATE = 3;
+        private static final int SET_RINGER_MODE = 4;
+        private static final int SET_ZEN_MODE = 5;
+        private static final int SET_EXIT_CONDITION = 6;
+        private static final int SET_STREAM_MUTE = 7;
+        private static final int LAYOUT_DIRECTION_CHANGED = 8;
+        private static final int CONFIGURATION_CHANGED = 9;
+        private static final int SET_STREAM_VOLUME = 10;
+        private static final int SET_ACTIVE_STREAM = 11;
+        private static final int NOTIFY_VISIBLE = 12;
+        private static final int USER_ACTIVITY = 13;
+        private static final int SHOW_SAFETY_WARNING = 14;
+
+        W(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case VOLUME_CHANGED: onVolumeChangedW(msg.arg1, msg.arg2); break;
+                case DISMISS_REQUESTED: onDismissRequestedW(msg.arg1); break;
+                case GET_STATE: onGetStateW(); break;
+                case SET_RINGER_MODE: onSetRingerModeW(msg.arg1, msg.arg2 != 0); break;
+                case SET_ZEN_MODE: onSetZenModeW(msg.arg1); break;
+                case SET_EXIT_CONDITION: onSetExitConditionW((Condition) msg.obj); break;
+                case SET_STREAM_MUTE: onSetStreamMuteW(msg.arg1, msg.arg2 != 0); break;
+                case LAYOUT_DIRECTION_CHANGED: mCallbacks.onLayoutDirectionChanged(msg.arg1); break;
+                case CONFIGURATION_CHANGED: mCallbacks.onConfigurationChanged(); break;
+                case SET_STREAM_VOLUME: onSetStreamVolumeW(msg.arg1, msg.arg2); break;
+                case SET_ACTIVE_STREAM: onSetActiveStreamW(msg.arg1); break;
+                case NOTIFY_VISIBLE: onNotifyVisibleW(msg.arg1 != 0); break;
+                case USER_ACTIVITY: onUserActivityW(); break;
+                case SHOW_SAFETY_WARNING: onShowSafetyWarningW(msg.arg1); break;
+            }
+        }
+    }
+
+    private final class C implements Callbacks {
+        private final HashMap<Callbacks, Handler> mCallbackMap = new HashMap<>();
+
+        public void add(Callbacks callback, Handler handler) {
+            if (callback == null || handler == null) throw new IllegalArgumentException();
+            mCallbackMap.put(callback, handler);
+        }
+
+        public void remove(Callbacks callback) {
+            mCallbackMap.remove(callback);
+        }
+
+        @Override
+        public void onShowRequested(final int reason) {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onShowRequested(reason);
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onDismissRequested(final int reason) {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onDismissRequested(reason);
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onStateChanged(final State state) {
+            final long time = System.currentTimeMillis();
+            final State copy = state.copy();
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onStateChanged(copy);
+                    }
+                });
+            }
+            Events.writeState(time, copy);
+        }
+
+        @Override
+        public void onLayoutDirectionChanged(final int layoutDirection) {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onLayoutDirectionChanged(layoutDirection);
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onConfigurationChanged() {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onConfigurationChanged();
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onShowVibrateHint() {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onShowVibrateHint();
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onShowSilentHint() {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onShowSilentHint();
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onScreenOff() {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onScreenOff();
+                    }
+                });
+            }
+        }
+
+        @Override
+        public void onShowSafetyWarning(final int flags) {
+            for (final Map.Entry<Callbacks, Handler> entry : mCallbackMap.entrySet()) {
+                entry.getValue().post(new Runnable() {
+                    @Override
+                    public void run() {
+                        entry.getKey().onShowSafetyWarning(flags);
+                    }
+                });
+            }
+        }
+    }
+
+
+    private final class SettingObserver extends ContentObserver {
+        private final Uri SERVICE_URI = Settings.Secure.getUriFor(
+                Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
+        private final Uri ZEN_MODE_URI =
+                Settings.Global.getUriFor(Settings.Global.ZEN_MODE);
+        private final Uri ZEN_MODE_CONFIG_URI =
+                Settings.Global.getUriFor(Settings.Global.ZEN_MODE_CONFIG_ETAG);
+
+        public SettingObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void init() {
+            mContext.getContentResolver().registerContentObserver(SERVICE_URI, false, this);
+            mContext.getContentResolver().registerContentObserver(ZEN_MODE_URI, false, this);
+            mContext.getContentResolver().registerContentObserver(ZEN_MODE_CONFIG_URI, false, this);
+            onChange(true, SERVICE_URI);
+        }
+
+        public void destroy() {
+            mContext.getContentResolver().unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            boolean changed = false;
+            if (SERVICE_URI.equals(uri)) {
+                final String setting = Settings.Secure.getString(mContext.getContentResolver(),
+                        Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
+                final boolean enabled = setting != null && mComponent != null
+                        && mComponent.equals(ComponentName.unflattenFromString(setting));
+                if (enabled == mEnabled) return;
+                if (enabled) {
+                    register();
+                }
+                mEnabled = enabled;
+            }
+            if (ZEN_MODE_URI.equals(uri)) {
+                changed = updateZenModeW();
+            }
+            if (ZEN_MODE_CONFIG_URI.equals(uri)) {
+                changed = updateExitConditionW();
+            }
+            if (changed) {
+                mCallbacks.onStateChanged(mState);
+            }
+        }
+    }
+
+    private final class Receiver extends BroadcastReceiver {
+
+        public void init() {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
+            filter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
+            filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
+            filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+            filter.addAction(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+            filter.addAction(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED);
+            filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            mContext.registerReceiver(this, filter, null, mWorker);
+        }
+
+        public void destroy() {
+            mContext.unregisterReceiver(this);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            boolean changed = false;
+            if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
+                final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                final int level = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1);
+                final int oldLevel = intent
+                        .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, -1);
+                if (D.BUG) Log.d(TAG, "onReceive VOLUME_CHANGED_ACTION stream=" + stream
+                        + " level=" + level + " oldLevel=" + oldLevel);
+                changed = updateStreamLevelW(stream, level);
+            } else if (action.equals(AudioManager.STREAM_DEVICES_CHANGED_ACTION)) {
+                final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                final int devices = intent
+                        .getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, -1);
+                final int oldDevices = intent
+                        .getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, -1);
+                if (D.BUG) Log.d(TAG, "onReceive STREAM_DEVICES_CHANGED_ACTION stream="
+                        + stream + " devices=" + devices + " oldDevices=" + oldDevices);
+                changed = checkRoutedToBluetoothW(stream);
+            } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION)) {
+                final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
+                if (D.BUG) Log.d(TAG, "onReceive RINGER_MODE_CHANGED_ACTION rm="
+                        + Util.ringerModeToString(rm));
+                changed = updateRingerModeExternalW(rm);
+            } else if (action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) {
+                final int rm = intent.getIntExtra(AudioManager.EXTRA_RINGER_MODE, -1);
+                if (D.BUG) Log.d(TAG, "onReceive INTERNAL_RINGER_MODE_CHANGED_ACTION rm="
+                        + Util.ringerModeToString(rm));
+                changed = updateRingerModeInternalW(rm);
+            } else if (action.equals(AudioManager.STREAM_MUTE_CHANGED_ACTION)) {
+                final int stream = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                final boolean muted = intent
+                        .getBooleanExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, false);
+                if (D.BUG) Log.d(TAG, "onReceive STREAM_MUTE_CHANGED_ACTION stream=" + stream
+                        + " muted=" + muted);
+                changed = updateStreamMuteW(stream, muted);
+            } else if (action.equals(NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED)) {
+                if (D.BUG) Log.d(TAG, "onReceive ACTION_EFFECTS_SUPPRESSOR_CHANGED");
+                changed = updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
+            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
+                if (D.BUG) Log.d(TAG, "onReceive ACTION_CONFIGURATION_CHANGED");
+                mCallbacks.onConfigurationChanged();
+            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
+                if (D.BUG) Log.d(TAG, "onReceive ACTION_SCREEN_OFF");
+                mCallbacks.onScreenOff();
+            }
+            if (changed) {
+                mCallbacks.onStateChanged(mState);
+            }
+        }
+    }
+
+    private final class MediaSessionsCallbacks implements MediaSessions.Callbacks {
+        private final HashMap<Token, Integer> mRemoteStreams = new HashMap<>();
+
+        private int mNextStream = DYNAMIC_STREAM_START_INDEX;
+
+        @Override
+        public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
+            if (!mRemoteStreams.containsKey(token)) {
+                mRemoteStreams.put(token, mNextStream);
+                if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + " is stream " + mNextStream);
+                mNextStream++;
+            }
+            final int stream = mRemoteStreams.get(token);
+            boolean changed = mState.states.indexOfKey(stream) < 0;
+            final StreamState ss = streamStateW(stream);
+            ss.dynamic = true;
+            ss.levelMin = 0;
+            ss.levelMax = pi.getMaxVolume();
+            if (ss.level != pi.getCurrentVolume()) {
+                ss.level = pi.getCurrentVolume();
+                changed = true;
+            }
+            if (!Objects.equals(ss.name, name)) {
+                ss.name = name;
+                changed = true;
+            }
+            if (changed) {
+                if (D.BUG) Log.d(TAG, "onRemoteUpdate: " + name + ": " + ss.level
+                        + " of " + ss.levelMax);
+                mCallbacks.onStateChanged(mState);
+            }
+        }
+
+        @Override
+        public void onRemoteVolumeChanged(Token token, int flags) {
+            final int stream = mRemoteStreams.get(token);
+            final boolean showUI = (flags & AudioManager.FLAG_SHOW_UI) != 0;
+            boolean changed = updateActiveStreamW(stream);
+            if (showUI) {
+                changed |= checkRoutedToBluetoothW(AudioManager.STREAM_MUSIC);
+            }
+            if (changed) {
+                mCallbacks.onStateChanged(mState);
+            }
+            if (showUI) {
+                mCallbacks.onShowRequested(Events.SHOW_REASON_REMOTE_VOLUME_CHANGED);
+            }
+        }
+
+        @Override
+        public void onRemoteRemoved(Token token) {
+            final int stream = mRemoteStreams.get(token);
+            mState.states.remove(stream);
+            if (mState.activeStream == stream) {
+                updateActiveStreamW(-1);
+            }
+            mCallbacks.onStateChanged(mState);
+        }
+
+        public void setStreamVolume(int stream, int level) {
+            final Token t = findToken(stream);
+            if (t == null) {
+                Log.w(TAG, "setStreamVolume: No token found for stream: " + stream);
+                return;
+            }
+            mMediaSessions.setVolume(t, level);
+        }
+
+        private Token findToken(int stream) {
+            for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
+                if (entry.getValue().equals(stream)) {
+                    return entry.getKey();
+                }
+            }
+            return null;
+        }
+    }
+
+    public static final class StreamState {
+        public boolean dynamic;
+        public int level;
+        public int levelMin;
+        public int levelMax;
+        public boolean muted;
+        public boolean muteSupported;
+        public String name;
+        public boolean routedToBluetooth;
+
+        public StreamState copy() {
+            final StreamState rt = new StreamState();
+            rt.dynamic = dynamic;
+            rt.level = level;
+            rt.levelMin = levelMin;
+            rt.levelMax = levelMax;
+            rt.muted = muted;
+            rt.muteSupported = muteSupported;
+            rt.name = name;
+            rt.routedToBluetooth = routedToBluetooth;
+            return rt;
+        }
+    }
+
+    public static final class State {
+        public static int NO_ACTIVE_STREAM = -1;
+
+        public final SparseArray<StreamState> states = new SparseArray<StreamState>();
+
+        public int ringerModeInternal;
+        public int ringerModeExternal;
+        public int zenMode;
+        public ComponentName effectsSuppressor;
+        public String effectsSuppressorName;
+        public Condition exitCondition;
+        public int activeStream = NO_ACTIVE_STREAM;
+
+        public State copy() {
+            final State rt = new State();
+            for (int i = 0; i < states.size(); i++) {
+                rt.states.put(states.keyAt(i), states.valueAt(i).copy());
+            }
+            rt.ringerModeExternal = ringerModeExternal;
+            rt.ringerModeInternal = ringerModeInternal;
+            rt.zenMode = zenMode;
+            if (effectsSuppressor != null) rt.effectsSuppressor = effectsSuppressor.clone();
+            rt.effectsSuppressorName = effectsSuppressorName;
+            if (exitCondition != null) rt.exitCondition = exitCondition.copy();
+            rt.activeStream = activeStream;
+            return rt;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("{");
+            for (int i = 0; i < states.size(); i++) {
+                if (i > 0) sb.append(',');
+                final int stream = states.keyAt(i);
+                final StreamState ss = states.valueAt(i);
+                sb.append(AudioSystem.streamToString(stream)).append(":").append(ss.level)
+                        .append("[").append(ss.levelMin).append("..").append(ss.levelMax);
+                if (ss.muted) sb.append(" [MUTED]");
+            }
+            sb.append(",ringerModeExternal:").append(ringerModeExternal);
+            sb.append(",ringerModeInternal:").append(ringerModeInternal);
+            sb.append(",zenMode:").append(zenMode);
+            sb.append(",effectsSuppressor:").append(effectsSuppressor);
+            sb.append(",effectsSuppressorName:").append(effectsSuppressorName);
+            sb.append(",exitCondition:").append(exitCondition);
+            sb.append(",activeStream:").append(activeStream);
+            return sb.append('}').toString();
+        }
+    }
+
+    public interface Callbacks {
+        void onShowRequested(int reason);
+        void onDismissRequested(int reason);
+        void onStateChanged(State state);
+        void onLayoutDirectionChanged(int layoutDirection);
+        void onConfigurationChanged();
+        void onShowVibrateHint();
+        void onShowSilentHint();
+        void onScreenOff();
+        void onShowSafetyWarning(int flags);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index d16b818..f16e9d2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -52,7 +52,6 @@
 import android.os.Vibrator;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -72,7 +71,6 @@
 
 import com.android.internal.R;
 import com.android.systemui.DemoMode;
-import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.io.FileDescriptor;
@@ -264,80 +262,6 @@
     private static AlertDialog sSafetyWarning;
     private static Object sSafetyWarningLock = new Object();
 
-    private static class SafetyWarning extends SystemUIDialog
-            implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
-        private final Context mContext;
-        private final VolumePanel mVolumePanel;
-        private final AudioManager mAudioManager;
-
-        private boolean mNewVolumeUp;
-
-        SafetyWarning(Context context, VolumePanel volumePanel, AudioManager audioManager) {
-            super(context);
-            mContext = context;
-            mVolumePanel = volumePanel;
-            mAudioManager = audioManager;
-
-            setMessage(mContext.getString(com.android.internal.R.string.safe_media_volume_warning));
-            setButton(DialogInterface.BUTTON_POSITIVE,
-                    mContext.getString(com.android.internal.R.string.yes), this);
-            setButton(DialogInterface.BUTTON_NEGATIVE,
-                    mContext.getString(com.android.internal.R.string.no), (OnClickListener) null);
-            setOnDismissListener(this);
-
-            IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
-            context.registerReceiver(mReceiver, filter);
-        }
-
-        @Override
-        public boolean onKeyDown(int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && event.getRepeatCount() == 0) {
-                mNewVolumeUp = true;
-            }
-            return super.onKeyDown(keyCode, event);
-        }
-
-        @Override
-        public boolean onKeyUp(int keyCode, KeyEvent event) {
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mNewVolumeUp) {
-                if (LOGD) Log.d(TAG, "Confirmed warning via VOLUME_UP");
-                mAudioManager.disableSafeMediaVolume();
-                dismiss();
-            }
-            return super.onKeyUp(keyCode, event);
-        }
-
-        @Override
-        public void onClick(DialogInterface dialog, int which) {
-            mAudioManager.disableSafeMediaVolume();
-        }
-
-        @Override
-        public void onDismiss(DialogInterface unused) {
-            mContext.unregisterReceiver(mReceiver);
-            cleanUp();
-        }
-
-        private void cleanUp() {
-            synchronized (sSafetyWarningLock) {
-                sSafetyWarning = null;
-            }
-            mVolumePanel.forceTimeout(0);
-            mVolumePanel.updateStates();
-        }
-
-        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                    if (LOGD) Log.d(TAG, "Received ACTION_CLOSE_SYSTEM_DIALOGS");
-                    cancel();
-                    cleanUp();
-                }
-            }
-        };
-    }
-
     protected LayoutParams getDialogLayoutParams(Window window, Resources res) {
         final LayoutParams lp = window.getAttributes();
         lp.token = null;
@@ -384,7 +308,7 @@
         final Window window = mDialog.getWindow();
         window.requestFeature(Window.FEATURE_NO_TITLE);
         mDialog.setCanceledOnTouchOutside(true);
-        mDialog.setContentView(com.android.systemui.R.layout.volume_dialog);
+        mDialog.setContentView(com.android.systemui.R.layout.volume_panel_dialog);
         mDialog.setOnDismissListener(new OnDismissListener() {
             @Override
             public void onDismiss(DialogInterface dialog) {
@@ -1283,7 +1207,16 @@
                 if (sSafetyWarning != null) {
                     return;
                 }
-                sSafetyWarning = new SafetyWarning(mContext, this, mAudioManager);
+                sSafetyWarning = new SafetyWarningDialog(mContext, mAudioManager) {
+                    @Override
+                    protected void cleanUp() {
+                        synchronized (sSafetyWarningLock) {
+                            sSafetyWarning = null;
+                        }
+                        forceTimeout(0);
+                        updateStates();
+                    }
+                };
                 sSafetyWarning.show();
             }
             updateStates();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java
new file mode 100644
index 0000000..fa6ea9e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.media.AudioManager;
+import android.media.IRemoteVolumeController;
+import android.media.IVolumeController;
+import android.media.VolumePolicy;
+import android.media.session.ISessionController;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.qs.tiles.DndTile;
+import com.android.systemui.statusbar.phone.PhoneStatusBar;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Implementation of VolumeComponent backed by the old volume panel.
+ */
+public class VolumePanelComponent implements VolumeComponent {
+
+    private final SystemUI mSysui;
+    private final Context mContext;
+    private final Handler mHandler;
+    private final VolumeController mVolumeController;
+    private final RemoteVolumeController mRemoteVolumeController;
+    private final AudioManager mAudioManager;
+    private final MediaSessionManager mMediaSessionManager;
+
+    private VolumePanel mPanel;
+    private int mDismissDelay;
+
+    public VolumePanelComponent(SystemUI sysui, Context context, Handler handler,
+            ZenModeController controller) {
+        mSysui = sysui;
+        mContext = context;
+        mHandler = handler;
+        mAudioManager = context.getSystemService(AudioManager.class);
+        mMediaSessionManager = context.getSystemService(MediaSessionManager.class);
+        mVolumeController = new VolumeController();
+        mRemoteVolumeController = new RemoteVolumeController();
+        mDismissDelay = mContext.getResources().getInteger(R.integer.volume_panel_dismiss_delay);
+        mPanel = new VolumePanel(mContext, controller);
+        mPanel.setCallback(new VolumePanel.Callback() {
+            @Override
+            public void onZenSettings() {
+                mHandler.removeCallbacks(mStartZenSettings);
+                mHandler.post(mStartZenSettings);
+            }
+
+            @Override
+            public void onInteraction() {
+                final KeyguardViewMediator kvm = mSysui.getComponent(KeyguardViewMediator.class);
+                if (kvm != null) {
+                    kvm.userActivity();
+                }
+            }
+
+            @Override
+            public void onVisible(boolean visible) {
+                if (mAudioManager != null && mVolumeController != null) {
+                    mAudioManager.notifyVolumeControllerVisible(mVolumeController, visible);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mPanel != null) {
+            mPanel.dump(fd, pw, args);
+        }
+    }
+
+    public void register() {
+        mAudioManager.setVolumeController(mVolumeController);
+        mAudioManager.setVolumePolicy(VolumePolicy.DEFAULT);
+        mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
+        DndTile.setVisible(mContext, false);
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (mPanel != null) {
+            mPanel.onConfigurationChanged(newConfig);
+        }
+    }
+
+    @Override
+    public ZenModeController getZenController() {
+        return mPanel.getZenController();
+    }
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        mPanel.dispatchDemoCommand(command, args);
+    }
+
+    @Override
+    public void dismissNow() {
+        mPanel.postDismiss(0);
+    }
+
+    private final Runnable mStartZenSettings = new Runnable() {
+        @Override
+        public void run() {
+            mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
+                    ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
+            mPanel.postDismiss(mDismissDelay);
+        }
+    };
+
+    private final class RemoteVolumeController extends IRemoteVolumeController.Stub {
+        @Override
+        public void remoteVolumeChanged(ISessionController binder, int flags)
+                throws RemoteException {
+            MediaController controller = new MediaController(mContext, binder);
+            mPanel.postRemoteVolumeChanged(controller, flags);
+        }
+
+        @Override
+        public void updateRemoteController(ISessionController session) throws RemoteException {
+            mPanel.postRemoteSliderVisibility(session != null);
+            // TODO stash default session in case the slider can be opened other
+            // than by remoteVolumeChanged.
+        }
+    }
+
+    /** For now, simply host an unmodified base volume panel in this process. */
+    private final class VolumeController extends IVolumeController.Stub {
+
+        @Override
+        public void displaySafeVolumeWarning(int flags) throws RemoteException {
+            mPanel.postDisplaySafeVolumeWarning(flags);
+        }
+
+        @Override
+        public void volumeChanged(int streamType, int flags)
+                throws RemoteException {
+            mPanel.postVolumeChanged(streamType, flags);
+        }
+
+        @Override
+        public void masterMuteChanged(int flags) throws RemoteException {
+            // no-op
+        }
+
+        @Override
+        public void setLayoutDirection(int layoutDirection)
+                throws RemoteException {
+            mPanel.postLayoutDirection(layoutDirection);
+        }
+
+        @Override
+        public void dismiss() throws RemoteException {
+            dismissNow();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index ac08904..387aed0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -29,25 +29,17 @@
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
 import android.media.AudioManager;
-import android.media.IRemoteVolumeController;
-import android.media.IVolumeController;
-import android.media.VolumePolicy;
-import android.media.session.ISessionController;
-import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
-import android.os.Bundle;
 import android.os.Handler;
-import android.os.RemoteException;
+import android.os.SystemProperties;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.statusbar.ServiceMonitor;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
@@ -59,6 +51,8 @@
     private static final String TAG = "VolumeUI";
     private static boolean LOGD = Log.isLoggable(TAG, Log.DEBUG);
 
+    private static final boolean USE_OLD_VOLUME = SystemProperties.getBoolean("volume.old", false);
+
     private final Handler mHandler = new Handler();
     private final Receiver mReceiver = new Receiver();
     private final RestorationNotification mRestorationNotification = new RestorationNotification();
@@ -67,12 +61,10 @@
     private AudioManager mAudioManager;
     private NotificationManager mNotificationManager;
     private MediaSessionManager mMediaSessionManager;
-    private VolumeController mVolumeController;
-    private RemoteVolumeController mRemoteVolumeController;
     private ServiceMonitor mVolumeControllerService;
 
-    private VolumePanel mPanel;
-    private int mDismissDelay;
+    private VolumePanelComponent mOldVolume;
+    private VolumeDialogComponent mNewVolume;
 
     @Override
     public void start() {
@@ -83,10 +75,10 @@
                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         mMediaSessionManager = (MediaSessionManager) mContext
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
-        initPanel();
-        mVolumeController = new VolumeController();
-        mRemoteVolumeController = new RemoteVolumeController();
-        putComponent(VolumeComponent.class, mVolumeController);
+        final ZenModeController zenController = new ZenModeControllerImpl(mContext, mHandler);
+        mOldVolume = new VolumePanelComponent(this, mContext, mHandler, zenController);
+        mNewVolume = new VolumeDialogComponent(this, mContext, null, zenController);
+        putComponent(VolumeComponent.class, getVolumeComponent());
         mReceiver.start();
         mVolumeControllerService = new ServiceMonitor(TAG, LOGD,
                 mContext, Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT,
@@ -94,30 +86,30 @@
         mVolumeControllerService.start();
     }
 
+    private VolumeComponent getVolumeComponent() {
+        return USE_OLD_VOLUME ? mOldVolume : mNewVolume;
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        if (mPanel != null) {
-            mPanel.onConfigurationChanged(newConfig);
-        }
+        if (!mEnabled) return;
+        getVolumeComponent().onConfigurationChanged(newConfig);
     }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mEnabled="); pw.println(mEnabled);
+        if (!mEnabled) return;
         pw.print("mVolumeControllerService="); pw.println(mVolumeControllerService.getComponent());
-        if (mPanel != null) {
-            mPanel.dump(fd, pw, args);
-        }
+        getVolumeComponent().dump(fd, pw, args);
     }
 
-    private void setVolumeController(boolean register) {
+    private void setDefaultVolumeController(boolean register) {
         if (register) {
-            if (LOGD) Log.d(TAG, "Registering default volume controller");
-            mAudioManager.setVolumeController(mVolumeController);
-            mAudioManager.setVolumePolicy(VolumePolicy.DEFAULT);
-            mMediaSessionManager.setRemoteVolumeController(mRemoteVolumeController);
             DndTile.setVisible(mContext, false);
+            if (LOGD) Log.d(TAG, "Registering default volume controller");
+            getVolumeComponent().register();
         } else {
             if (LOGD) Log.d(TAG, "Unregistering default volume controller");
             mAudioManager.setVolumeController(null);
@@ -125,33 +117,6 @@
         }
     }
 
-    private void initPanel() {
-        mDismissDelay = mContext.getResources().getInteger(R.integer.volume_panel_dismiss_delay);
-        mPanel = new VolumePanel(mContext, new ZenModeControllerImpl(mContext, mHandler));
-        mPanel.setCallback(new VolumePanel.Callback() {
-            @Override
-            public void onZenSettings() {
-                mHandler.removeCallbacks(mStartZenSettings);
-                mHandler.post(mStartZenSettings);
-            }
-
-            @Override
-            public void onInteraction() {
-                final KeyguardViewMediator kvm = getComponent(KeyguardViewMediator.class);
-                if (kvm != null) {
-                    kvm.userActivity();
-                }
-            }
-
-            @Override
-            public void onVisible(boolean visible) {
-                if (mAudioManager != null && mVolumeController != null) {
-                    mAudioManager.notifyVolumeControllerVisible(mVolumeController, visible);
-                }
-            }
-        });
-    }
-
     private String getAppLabel(ComponentName component) {
         final String pkg = component.getPackageName();
         try {
@@ -179,83 +144,11 @@
         d.show();
     }
 
-    private final Runnable mStartZenSettings = new Runnable() {
-        @Override
-        public void run() {
-            getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
-                    ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
-            mPanel.postDismiss(mDismissDelay);
-        }
-    };
-
-    /** For now, simply host an unmodified base volume panel in this process. */
-    private final class VolumeController extends IVolumeController.Stub implements VolumeComponent {
-
-        @Override
-        public void displaySafeVolumeWarning(int flags) throws RemoteException {
-            mPanel.postDisplaySafeVolumeWarning(flags);
-        }
-
-        @Override
-        public void volumeChanged(int streamType, int flags)
-                throws RemoteException {
-            mPanel.postVolumeChanged(streamType, flags);
-        }
-
-        @Override
-        public void masterMuteChanged(int flags) throws RemoteException {
-            // no-op
-        }
-
-        @Override
-        public void setLayoutDirection(int layoutDirection)
-                throws RemoteException {
-            mPanel.postLayoutDirection(layoutDirection);
-        }
-
-        @Override
-        public void dismiss() throws RemoteException {
-            dismissNow();
-        }
-
-        @Override
-        public ZenModeController getZenController() {
-            return mPanel.getZenController();
-        }
-
-        @Override
-        public void dispatchDemoCommand(String command, Bundle args) {
-            mPanel.dispatchDemoCommand(command, args);
-        }
-
-        @Override
-        public void dismissNow() {
-            mPanel.postDismiss(0);
-        }
-    }
-
-    private final class RemoteVolumeController extends IRemoteVolumeController.Stub {
-
-        @Override
-        public void remoteVolumeChanged(ISessionController binder, int flags)
-                throws RemoteException {
-            MediaController controller = new MediaController(mContext, binder);
-            mPanel.postRemoteVolumeChanged(controller, flags);
-        }
-
-        @Override
-        public void updateRemoteController(ISessionController session) throws RemoteException {
-            mPanel.postRemoteSliderVisibility(session != null);
-            // TODO stash default session in case the slider can be opened other
-            // than by remoteVolumeChanged.
-        }
-    }
-
     private final class ServiceMonitorCallbacks implements ServiceMonitor.Callbacks {
         @Override
         public void onNoService() {
             if (LOGD) Log.d(TAG, "onNoService");
-            setVolumeController(true);
+            setDefaultVolumeController(true);
             mRestorationNotification.hide();
             if (!mVolumeControllerService.isPackageAvailable()) {
                 mVolumeControllerService.setComponent(null);
@@ -267,8 +160,8 @@
             if (LOGD) Log.d(TAG, "onServiceStartAttempt");
             // poke the setting to update the uid
             mVolumeControllerService.setComponent(mVolumeControllerService.getComponent());
-            setVolumeController(false);
-            mVolumeController.dismissNow();
+            setDefaultVolumeController(false);
+            getVolumeComponent().dismissNow();
             mRestorationNotification.show();
             return 0;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
new file mode 100644
index 0000000..ef8257c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.volume;
+
+import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.res.Resources;
+import android.provider.Settings.Global;
+import android.service.notification.ZenModeConfig;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.LinearLayout;
+import android.widget.Switch;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+
+import java.util.Objects;
+
+/**
+ * Switch bar + zen mode panel (conditions) attached to the bottom of the volume dialog.
+ */
+public class ZenFooter extends LinearLayout {
+    private static final String TAG = Util.logTag(ZenFooter.class);
+
+    private final Context mContext;
+    private final float mSecondaryAlpha;
+    private final LayoutTransition mLayoutTransition;
+
+    private ZenModeController mController;
+    private Switch mSwitch;
+    private ZenModePanel mZenModePanel;
+    private View mZenModePanelButtons;
+    private View mZenModePanelMoreButton;
+    private View mZenModePanelDoneButton;
+    private View mSwitchBar;
+    private View mSwitchBarIcon;
+    private View mSummary;
+    private TextView mSummaryLine1;
+    private TextView mSummaryLine2;
+    private boolean mFooterExpanded;
+    private int mZen = -1;
+    private ZenModeConfig mConfig;
+    private Callback mCallback;
+
+    public ZenFooter(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+        mSecondaryAlpha = getFloat(context.getResources(), R.dimen.volume_secondary_alpha);
+        mLayoutTransition = new LayoutTransition();
+        mLayoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
+        mLayoutTransition.disableTransitionType(LayoutTransition.DISAPPEARING);
+        mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_DISAPPEARING);
+    }
+
+    private static float getFloat(Resources r, int resId) {
+        final TypedValue tv = new TypedValue();
+        r.getValue(resId, tv, true);
+        return tv.getFloat();
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mSwitchBar = findViewById(R.id.volume_zen_switch_bar);
+        mSwitchBarIcon = findViewById(R.id.volume_zen_switch_bar_icon);
+        mSwitch = (Switch) findViewById(R.id.volume_zen_switch);
+        mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
+        mZenModePanelButtons = findViewById(R.id.volume_zen_mode_panel_buttons);
+        mZenModePanelMoreButton = findViewById(R.id.volume_zen_mode_panel_more);
+        mZenModePanelDoneButton = findViewById(R.id.volume_zen_mode_panel_done);
+        mSummary = findViewById(R.id.volume_zen_panel_summary);
+        mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_1);
+        mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_panel_summary_line_2);
+    }
+
+    public void init(ZenModeController controller, Callback callback) {
+        mCallback = callback;
+        mController = controller;
+        mZenModePanel.init(controller);
+        mZenModePanel.setEmbedded(true);
+        mSwitch.setOnCheckedChangeListener(mCheckedListener);
+        mController.addCallback(new ZenModeController.Callback() {
+            @Override
+            public void onZenChanged(int zen) {
+                setZen(zen);
+            }
+            @Override
+            public void onConfigChanged(ZenModeConfig config) {
+                setConfig(config);
+            }
+        });
+        mSwitchBar.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mSwitch.setChecked(!mSwitch.isChecked());
+            }
+        });
+        mZenModePanelMoreButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mCallback != null) {
+                    mCallback.onSettingsClicked();
+                }
+            }
+        });
+        mZenModePanelDoneButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mCallback != null) {
+                    mCallback.onDoneClicked();
+                }
+            }
+        });
+        mZen = mController.getZen();
+        mConfig = mController.getConfig();
+        update();
+    }
+
+    private void setZen(int zen) {
+        if (mZen == zen) return;
+        mZen = zen;
+        update();
+    }
+
+    private void setConfig(ZenModeConfig config) {
+        if (Objects.equals(mConfig, config)) return;
+        mConfig = config;
+        update();
+    }
+
+    public boolean isZen() {
+        return isZenPriority() || isZenAlarms() || isZenNone();
+    }
+
+    private boolean isZenPriority() {
+        return mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+    }
+
+    private boolean isZenAlarms() {
+        return mZen == Global.ZEN_MODE_ALARMS;
+    }
+
+    private boolean isZenNone() {
+        return mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        setLayoutTransition(null);
+        setFooterExpanded(false);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        setLayoutTransition(mLayoutTransition);
+    }
+
+    private boolean setFooterExpanded(boolean expanded) {
+        if (mFooterExpanded == expanded) return false;
+        mFooterExpanded = expanded;
+        update();
+        if (mCallback != null) {
+            mCallback.onFooterExpanded();
+        }
+        return true;
+    }
+
+    public boolean isFooterExpanded() {
+        return mFooterExpanded;
+    }
+
+    public void update() {
+        final boolean isZen = isZen();
+        mSwitch.setOnCheckedChangeListener(null);
+        mSwitch.setChecked(isZen);
+        mSwitch.setOnCheckedChangeListener(mCheckedListener);
+        Util.setVisOrGone(mZenModePanel, isZen && mFooterExpanded);
+        Util.setVisOrGone(mZenModePanelButtons, isZen && mFooterExpanded);
+        Util.setVisOrGone(mSummary, isZen && !mFooterExpanded);
+        mSwitchBarIcon.setAlpha(isZen ? 1 : mSecondaryAlpha);
+        final String line1 =
+                isZenPriority() ? mContext.getString(R.string.interruption_level_priority)
+                : isZenAlarms() ? mContext.getString(R.string.interruption_level_alarms)
+                : isZenNone() ? mContext.getString(R.string.interruption_level_none)
+                : null;
+        Util.setText(mSummaryLine1, line1);
+        final String line2 = ZenModeConfig.getConditionSummary(mContext, mConfig,
+                ActivityManager.getCurrentUser());
+        Util.setText(mSummaryLine2, line2);
+    }
+
+    private final OnCheckedChangeListener mCheckedListener = new OnCheckedChangeListener() {
+        @Override
+        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+            if (D.BUG) Log.d(TAG, "onCheckedChanged " + isChecked);
+            if (isChecked != isZen()) {
+                final int newZen = isChecked ? Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+                        : Global.ZEN_MODE_OFF;
+                mZen = newZen;  // this one's optimistic
+                setFooterExpanded(isChecked);
+                mController.setZen(newZen, null, TAG);
+            }
+        }
+    };
+
+    public interface Callback {
+        void onFooterExpanded();
+        void onSettingsClicked();
+        void onDoneClicked();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 878ab712..f6d4c36 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -23,7 +23,6 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.content.res.Resources;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Handler;
@@ -33,6 +32,7 @@
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ZenRule;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.AttributeSet;
@@ -150,14 +150,14 @@
         if (mEmbedded == embedded) return;
         mEmbedded = embedded;
         mZenButtonsContainer.setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
+        setLayoutTransition(mEmbedded ? null : newLayoutTransition(null));
         if (mEmbedded) {
             mZenButtonsContainer.setBackground(null);
         } else {
             mZenButtonsContainer.setBackgroundResource(R.drawable.qs_background_secondary);
         }
-        mZenButtons.getChildAt(2).setVisibility(mEmbedded ? GONE : VISIBLE);
+        mZenButtons.getChildAt(3).setVisibility(mEmbedded ? GONE : VISIBLE);
         mZenEmbeddedDivider.setVisibility(mEmbedded ? VISIBLE : GONE);
-        setExpanded(mEmbedded);
         updateWidgets();
     }
 
@@ -166,12 +166,13 @@
         super.onFinishInflate();
 
         mZenButtons = (SegmentedButtons) findViewById(R.id.zen_buttons);
-        mZenButtons.addButton(R.string.interruption_level_none, R.drawable.ic_zen_none,
+        mZenButtons.addButton(R.string.interruption_level_none_twoline,
                 Global.ZEN_MODE_NO_INTERRUPTIONS);
-        mZenButtons.addButton(R.string.interruption_level_priority, R.drawable.ic_zen_important,
+        mZenButtons.addButton(R.string.interruption_level_alarms_twoline,
+                Global.ZEN_MODE_ALARMS);
+        mZenButtons.addButton(R.string.interruption_level_priority_twoline,
                 Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
-        mZenButtons.addButton(R.string.interruption_level_all, R.drawable.ic_zen_all,
-                Global.ZEN_MODE_OFF);
+        mZenButtons.addButton(R.string.interruption_level_all, Global.ZEN_MODE_OFF);
         mZenButtons.setCallback(mZenButtonsCallback);
 
         mZenButtonsContainer = (ViewGroup) findViewById(R.id.zen_buttons_container);
@@ -275,8 +276,9 @@
 
     private void setExpanded(boolean expanded) {
         if (expanded == mExpanded) return;
+        if (DEBUG) Log.d(mTag, "setExpanded " + expanded);
         mExpanded = expanded;
-        if (mExpanded) {
+        if (mExpanded && isShown()) {
             ensureSelection();
         }
         updateWidgets();
@@ -297,7 +299,7 @@
             });
         }
         if (mRequestingConditions) {
-            mTimeCondition = parseExistingTimeCondition(mExitCondition);
+            mTimeCondition = parseExistingTimeCondition(mContext, mExitCondition);
             if (mTimeCondition != null) {
                 mBucketIndex = -1;
             } else {
@@ -325,10 +327,9 @@
         for (int i = 0; i < mMaxConditions; i++) {
             mZenConditions.addView(mInflater.inflate(R.layout.zen_mode_condition, this, false));
         }
-        setExitCondition(mController.getExitCondition());
         refreshExitConditionText();
         mSessionZen = getSelectedZen(-1);
-        handleUpdateZen(mController.getZen());
+        handleUpdateManualRule(mController.getManualRule());
         if (DEBUG) Log.d(mTag, "init mExitCondition=" + mExitCondition);
         hideAllConditions();
         mController.addCallback(mZenCallback);
@@ -350,6 +351,10 @@
         return condition != null ? condition.id : null;
     }
 
+    private Uri getRealConditionId(Condition condition) {
+        return isForever(condition) ? null : getConditionId(condition);
+    }
+
     private static boolean sameConditionId(Condition lhs, Condition rhs) {
         return lhs == null ? rhs == null : rhs != null && lhs.id.equals(rhs.id);
     }
@@ -359,13 +364,17 @@
     }
 
     private void refreshExitConditionText() {
-        if (mExitCondition == null) {
-            mExitConditionText = foreverSummary();
-        } else if (isCountdown(mExitCondition)) {
-            final Condition condition = parseExistingTimeCondition(mExitCondition);
-            mExitConditionText = condition != null ? condition.summary : foreverSummary();
+        mExitConditionText = getExitConditionText(mContext, mExitCondition);
+    }
+
+    public static String getExitConditionText(Context context, Condition exitCondition) {
+        if (exitCondition == null) {
+            return foreverSummary(context);
+        } else if (isCountdown(exitCondition)) {
+            final Condition condition = parseExistingTimeCondition(context, exitCondition);
+            return condition != null ? condition.summary : foreverSummary(context);
         } else {
-            mExitConditionText = mExitCondition.summary;
+            return exitCondition.summary;
         }
     }
 
@@ -380,9 +389,16 @@
         mIconPulser.start(noneButton);
     }
 
+    private void handleUpdateManualRule(ZenRule rule) {
+        final int zen = rule != null ? rule.zenMode : Global.ZEN_MODE_OFF;
+        handleUpdateZen(zen);
+        final Condition c = rule != null ? rule.condition : null;
+        handleExitConditionChanged(c);
+    }
+
     private void handleUpdateZen(int zen) {
         if (mSessionZen != -1 && mSessionZen != zen) {
-            setExpanded(mEmbedded || zen != Global.ZEN_MODE_OFF);
+            setExpanded(mEmbedded && isShown() || !mEmbedded && zen != Global.ZEN_MODE_OFF);
             mSessionZen = zen;
         }
         mZenButtons.setSelectedValue(zen);
@@ -396,6 +412,20 @@
         }
     }
 
+    private void handleExitConditionChanged(Condition exitCondition) {
+        setExitCondition(exitCondition);
+        if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
+        final int N = getVisibleConditions();
+        for (int i = 0; i < N; i++) {
+            final ConditionTag tag = getConditionTagAt(i);
+            if (tag != null) {
+                if (sameConditionId(tag.condition, mExitCondition)) {
+                    bind(exitCondition, mZenConditions.getChildAt(i));
+                }
+            }
+        }
+    }
+
     private Condition getSelectedCondition() {
         final int N = getVisibleConditions();
         for (int i = 0; i < N; i++) {
@@ -428,7 +458,7 @@
         mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
         mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
         mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
-        mZenConditions.setVisibility(!zenOff && expanded ? VISIBLE : GONE);
+        mZenConditions.setVisibility(mEmbedded || !zenOff && expanded ? VISIBLE : GONE);
 
         if (zenNone) {
             mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning);
@@ -441,14 +471,14 @@
                 ? mSubheadWarningColor : mSubheadColor);
     }
 
-    private Condition parseExistingTimeCondition(Condition condition) {
+    private static Condition parseExistingTimeCondition(Context context, Condition condition) {
         if (condition == null) return null;
         final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id);
         if (time == 0) return null;
         final long now = System.currentTimeMillis();
         final long span = time - now;
         if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null;
-        return ZenModeConfig.toTimeCondition(mContext,
+        return ZenModeConfig.toTimeCondition(context,
                 time, Math.round(span / (float) MINUTES_MS), now, ActivityManager.getCurrentUser());
     }
 
@@ -508,18 +538,18 @@
             mZenConditions.getChildAt(i).setVisibility(GONE);
         }
         // ensure something is selected
-        if (mExpanded) {
+        if (mExpanded && isShown()) {
             ensureSelection();
         }
     }
 
     private Condition forever() {
-        return new Condition(mForeverId, foreverSummary(), "", "", 0 /*icon*/, Condition.STATE_TRUE,
-                0 /*flags*/);
+        return new Condition(mForeverId, foreverSummary(mContext), "", "", 0 /*icon*/,
+                Condition.STATE_TRUE, 0 /*flags*/);
     }
 
-    private String foreverSummary() {
-        return mContext.getString(com.android.internal.R.string.zen_mode_forever);
+    private static String foreverSummary(Context context) {
+        return context.getString(com.android.internal.R.string.zen_mode_forever);
     }
 
     private ConditionTag getConditionTagAt(int index) {
@@ -568,21 +598,7 @@
         }
     }
 
-    private void handleExitConditionChanged(Condition exitCondition) {
-        setExitCondition(exitCondition);
-        if (DEBUG) Log.d(mTag, "handleExitConditionChanged " + mExitCondition);
-        final int N = getVisibleConditions();
-        for (int i = 0; i < N; i++) {
-            final ConditionTag tag = getConditionTagAt(i);
-            if (tag != null) {
-                if (sameConditionId(tag.condition, mExitCondition)) {
-                    bind(exitCondition, mZenConditions.getChildAt(i));
-                }
-            }
-        }
-    }
-
-    private boolean isCountdown(Condition c) {
+    private static boolean isCountdown(Condition c) {
         return c != null && ZenModeConfig.isValidCountdownConditionId(c.id);
     }
 
@@ -715,7 +731,10 @@
             case Global.ZEN_MODE_NO_INTERRUPTIONS:
                 modeText = mContext.getString(R.string.zen_no_interruptions);
                 break;
-             default:
+            case Global.ZEN_MODE_ALARMS:
+                modeText = mContext.getString(R.string.zen_alarms);
+                break;
+            default:
                 return;
         }
         announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText,
@@ -761,17 +780,21 @@
 
     private void select(final Condition condition) {
         if (DEBUG) Log.d(mTag, "select " + condition);
-        final boolean isForever = isForever(condition);
+        if (mSessionZen == -1 || mSessionZen == Global.ZEN_MODE_OFF) {
+            if (DEBUG) Log.d(mTag, "Ignoring condition selection outside of manual zen");
+            return;
+        }
+        final Uri realConditionId = getRealConditionId(condition);
         if (mController != null) {
             AsyncTask.execute(new Runnable() {
                 @Override
                 public void run() {
-                    mController.setExitCondition(isForever ? null : condition);
+                    mController.setZen(mSessionZen, realConditionId, TAG + ".selectCondition");
                 }
             });
         }
         setExitCondition(condition);
-        if (isForever) {
+        if (realConditionId == null) {
             mPrefs.setMinuteIndex(-1);
         } else if (isCountdown(condition) && mBucketIndex != -1) {
             mPrefs.setMinuteIndex(mBucketIndex);
@@ -799,24 +822,19 @@
 
     private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
         @Override
-        public void onZenChanged(int zen) {
-            mHandler.obtainMessage(H.UPDATE_ZEN, zen, 0).sendToTarget();
-        }
-        @Override
         public void onConditionsChanged(Condition[] conditions) {
             mHandler.obtainMessage(H.UPDATE_CONDITIONS, conditions).sendToTarget();
         }
 
         @Override
-        public void onExitConditionChanged(Condition exitCondition) {
-            mHandler.obtainMessage(H.EXIT_CONDITION_CHANGED, exitCondition).sendToTarget();
+        public void onManualRuleChanged(ZenRule rule) {
+            mHandler.obtainMessage(H.MANUAL_RULE_CHANGED, rule).sendToTarget();
         }
     };
 
     private final class H extends Handler {
         private static final int UPDATE_CONDITIONS = 1;
-        private static final int EXIT_CONDITION_CHANGED = 2;
-        private static final int UPDATE_ZEN = 3;
+        private static final int MANUAL_RULE_CHANGED = 2;
 
         private H() {
             super(Looper.getMainLooper());
@@ -826,10 +844,8 @@
         public void handleMessage(Message msg) {
             if (msg.what == UPDATE_CONDITIONS) {
                 handleUpdateConditions((Condition[]) msg.obj);
-            } else if (msg.what == EXIT_CONDITION_CHANGED) {
-                handleExitConditionChanged((Condition) msg.obj);
-            } else if (msg.what == UPDATE_ZEN) {
-                handleUpdateZen(msg.arg1);
+            } else if (msg.what == MANUAL_RULE_CHANGED) {
+                handleUpdateManualRule((ZenRule) msg.obj);
             }
         }
     }
@@ -921,12 +937,13 @@
     private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
         @Override
         public void onSelected(final Object value) {
-            if (value != null && mZenButtons.isShown()) {
+            if (value != null && mZenButtons.isShown() && isAttachedToWindow()) {
                 if (DEBUG) Log.d(mTag, "mZenButtonsCallback selected=" + value);
+                final Uri realConditionId = getRealConditionId(mSessionExitCondition);
                 AsyncTask.execute(new Runnable() {
                     @Override
                     public void run() {
-                        mController.setZen((Integer) value);
+                        mController.setZen((Integer) value, realConditionId, TAG + ".selectZen");
                     }
                 });
             }
diff --git a/preloaded-classes b/preloaded-classes
index c8d8c5d..151766f 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1146,8 +1146,6 @@
 android.provider.Settings$System
 android.provider.Telephony$Mms
 android.renderscript.RenderScript
-android.security.AndroidKeyPairGenerator
-android.security.AndroidKeyStore
 android.security.AndroidKeyStoreProvider
 android.speech.tts.TextToSpeechService
 android.speech.tts.TextToSpeechService$SpeechItemV1
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 2b2e611..2203850 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -1340,15 +1340,22 @@
 
     private void copyTo(Object array, Element.DataType dt, int arrayLen) {
         Trace.traceBegin(RenderScript.TRACE_TAG, "copyTo");
-        if (dt.mSize * arrayLen < mSize) {
-            throw new RSIllegalArgumentException(
-                "Size of output array cannot be smaller than size of allocation.");
-        }
         mRS.validate();
         boolean usePadding = false;
         if (mAutoPadding && (mType.getElement().getVectorSize() == 3)) {
             usePadding = true;
         }
+        if (usePadding) {
+            if (dt.mSize * arrayLen < mSize / 4 * 3) {
+                throw new RSIllegalArgumentException(
+                    "Size of output array cannot be smaller than size of allocation.");
+            }
+        } else {
+            if (dt.mSize * arrayLen < mSize) {
+                throw new RSIllegalArgumentException(
+                    "Size of output array cannot be smaller than size of allocation.");
+            }
+        }
         mRS.nAllocationRead(getID(mRS), array, dt, mType.mElement.mType.mSize, usePadding);
         Trace.traceEnd(RenderScript.TRACE_TAG);
     }
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 0f967fc..de1c497 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -47,6 +47,15 @@
         // subAlign() can never work correctly for copied FieldPacker objects.
     }
 
+    static FieldPacker createFromArray(Object[] args) {
+        FieldPacker fp = new FieldPacker(RenderScript.sPointerSize * 8);
+        for (Object arg : args) {
+            fp.addSafely(arg);
+        }
+        fp.resize(fp.mPos);
+        return fp;
+    }
+
     public void align(int v) {
         if ((v <= 0) || ((v & (v - 1)) != 0)) {
             throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
@@ -618,294 +627,182 @@
         return mPos;
     }
 
-    private static void addToPack(FieldPacker fp, Object obj) {
+    private void add(Object obj) {
         if (obj instanceof Boolean) {
-            fp.addBoolean(((Boolean)obj).booleanValue());
+            addBoolean((Boolean)obj);
             return;
         }
 
         if (obj instanceof Byte) {
-            fp.addI8(((Byte)obj).byteValue());
+            addI8((Byte)obj);
             return;
         }
 
         if (obj instanceof Short) {
-            fp.addI16(((Short)obj).shortValue());
+            addI16((Short)obj);
             return;
         }
 
         if (obj instanceof Integer) {
-            fp.addI32(((Integer)obj).intValue());
+            addI32((Integer)obj);
             return;
         }
 
         if (obj instanceof Long) {
-            fp.addI64(((Long)obj).longValue());
+            addI64((Long)obj);
             return;
         }
 
         if (obj instanceof Float) {
-            fp.addF32(((Float)obj).floatValue());
+            addF32((Float)obj);
             return;
         }
 
         if (obj instanceof Double) {
-            fp.addF64(((Double)obj).doubleValue());
+            addF64((Double)obj);
             return;
         }
 
         if (obj instanceof Byte2) {
-            fp.addI8((Byte2)obj);
+            addI8((Byte2)obj);
             return;
         }
 
         if (obj instanceof Byte3) {
-            fp.addI8((Byte3)obj);
+            addI8((Byte3)obj);
             return;
         }
 
         if (obj instanceof Byte4) {
-            fp.addI8((Byte4)obj);
+            addI8((Byte4)obj);
             return;
         }
 
         if (obj instanceof Short2) {
-            fp.addI16((Short2)obj);
+            addI16((Short2)obj);
             return;
         }
 
         if (obj instanceof Short3) {
-            fp.addI16((Short3)obj);
+            addI16((Short3)obj);
             return;
         }
 
         if (obj instanceof Short4) {
-            fp.addI16((Short4)obj);
+            addI16((Short4)obj);
             return;
         }
 
         if (obj instanceof Int2) {
-            fp.addI32((Int2)obj);
+            addI32((Int2)obj);
             return;
         }
 
         if (obj instanceof Int3) {
-            fp.addI32((Int3)obj);
+            addI32((Int3)obj);
             return;
         }
 
         if (obj instanceof Int4) {
-            fp.addI32((Int4)obj);
+            addI32((Int4)obj);
             return;
         }
 
         if (obj instanceof Long2) {
-            fp.addI64((Long2)obj);
+            addI64((Long2)obj);
             return;
         }
 
         if (obj instanceof Long3) {
-            fp.addI64((Long3)obj);
+            addI64((Long3)obj);
             return;
         }
 
         if (obj instanceof Long4) {
-            fp.addI64((Long4)obj);
+            addI64((Long4)obj);
             return;
         }
 
         if (obj instanceof Float2) {
-            fp.addF32((Float2)obj);
+            addF32((Float2)obj);
             return;
         }
 
         if (obj instanceof Float3) {
-            fp.addF32((Float3)obj);
+            addF32((Float3)obj);
             return;
         }
 
         if (obj instanceof Float4) {
-            fp.addF32((Float4)obj);
+            addF32((Float4)obj);
             return;
         }
 
         if (obj instanceof Double2) {
-            fp.addF64((Double2)obj);
+            addF64((Double2)obj);
             return;
         }
 
         if (obj instanceof Double3) {
-            fp.addF64((Double3)obj);
+            addF64((Double3)obj);
             return;
         }
 
         if (obj instanceof Double4) {
-            fp.addF64((Double4)obj);
+            addF64((Double4)obj);
             return;
         }
 
         if (obj instanceof Matrix2f) {
-            fp.addMatrix((Matrix2f)obj);
+            addMatrix((Matrix2f)obj);
             return;
         }
 
         if (obj instanceof Matrix3f) {
-            fp.addMatrix((Matrix3f)obj);
+            addMatrix((Matrix3f)obj);
             return;
         }
 
         if (obj instanceof Matrix4f) {
-            fp.addMatrix((Matrix4f)obj);
+            addMatrix((Matrix4f)obj);
             return;
         }
 
         if (obj instanceof BaseObj) {
-            fp.addObj((BaseObj)obj);
+            addObj((BaseObj)obj);
             return;
         }
     }
 
-    private static int getPackedSize(Object obj) {
-        if (obj instanceof Boolean) {
-            return 1;
+    private boolean resize(int newSize) {
+        if (newSize == mLen) {
+            return false;
         }
 
-        if (obj instanceof Byte) {
-            return 1;
-        }
+        byte[] newData = new byte[newSize];
+        System.arraycopy(mData, 0, newData, 0, mPos);
+        mData = newData;
+        mLen = newSize;
+        return true;
+    }
 
-        if (obj instanceof Short) {
-            return 2;
-        }
-
-        if (obj instanceof Integer) {
-            return 4;
-        }
-
-        if (obj instanceof Long) {
-            return 8;
-        }
-
-        if (obj instanceof Float) {
-            return 4;
-        }
-
-        if (obj instanceof Double) {
-            return 8;
-        }
-
-        if (obj instanceof Byte2) {
-            return 2;
-        }
-
-        if (obj instanceof Byte3) {
-            return 3;
-        }
-
-        if (obj instanceof Byte4) {
-            return 4;
-        }
-
-        if (obj instanceof Short2) {
-            return 4;
-        }
-
-        if (obj instanceof Short3) {
-            return 6;
-        }
-
-        if (obj instanceof Short4) {
-            return 8;
-        }
-
-        if (obj instanceof Int2) {
-            return 8;
-        }
-
-        if (obj instanceof Int3) {
-            return 12;
-        }
-
-        if (obj instanceof Int4) {
-            return 16;
-        }
-
-        if (obj instanceof Long2) {
-            return 16;
-        }
-
-        if (obj instanceof Long3) {
-            return 24;
-        }
-
-        if (obj instanceof Long4) {
-            return 32;
-        }
-
-        if (obj instanceof Float2) {
-            return 8;
-        }
-
-        if (obj instanceof Float3) {
-            return 12;
-        }
-
-        if (obj instanceof Float4) {
-            return 16;
-        }
-
-        if (obj instanceof Double2) {
-            return 16;
-        }
-
-        if (obj instanceof Double3) {
-            return 24;
-        }
-
-        if (obj instanceof Double4) {
-            return 32;
-        }
-
-        if (obj instanceof Matrix2f) {
-            return 16;
-        }
-
-        if (obj instanceof Matrix3f) {
-            return 36;
-        }
-
-        if (obj instanceof Matrix4f) {
-            return 64;
-        }
-
-        if (obj instanceof BaseObj) {
-            if (RenderScript.sPointerSize == 8) {
-                return 32;
-            } else {
-                return 4;
+    private void addSafely(Object obj) {
+        boolean retry;
+        final int oldPos = mPos;
+        do {
+            retry = false;
+            try {
+                add(obj);
+            } catch (ArrayIndexOutOfBoundsException e) {
+                mPos = oldPos;
+                resize(mLen * 2);
+                retry = true;
             }
-        }
-
-        return 0;
+        } while (retry);
     }
 
-    static FieldPacker createFieldPack(Object[] args) {
-        int len = 0;
-        for (Object arg : args) {
-            len += getPackedSize(arg);
-        }
-        FieldPacker fp = new FieldPacker(len);
-        for (Object arg : args) {
-            addToPack(fp, arg);
-        }
-        return fp;
-    }
-
-    private final byte mData[];
+    private byte mData[];
     private int mPos;
     private int mLen;
     private BitSet mAlignment;
-
 }
-
-
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 7ef17a7..5fc1f93 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -129,8 +129,6 @@
     native void nContextInitToClient(long con);
     native void nContextDeinitToClient(long con);
 
-    static File mCacheDir;
-
     // this should be a monotonically increasing ID
     // used in conjunction with the API version of a device
     static final long sMinorID = 1;
@@ -146,23 +144,6 @@
         return sMinorID;
     }
 
-     /**
-     * Sets the directory to use as a persistent storage for the
-     * renderscript object file cache.
-     *
-     * @hide
-     * @param cacheDir A directory the current process can write to
-     */
-    public static void setupDiskCache(File cacheDir) {
-        if (!sInitialized) {
-            Log.e(LOG_TAG, "RenderScript.setupDiskCache() called when disabled");
-            return;
-        }
-
-        // Defer creation of cache path to nScriptCCreate().
-        mCacheDir = cacheDir;
-    }
-
     /**
      * ContextType specifies the specific type of context to be created.
      *
@@ -251,6 +232,11 @@
         validate();
         rsnContextSetPriority(mContext, p);
     }
+    native void rsnContextSetCacheDir(long con, String cacheDir);
+    synchronized void nContextSetCacheDir(String cacheDir) {
+        validate();
+        rsnContextSetCacheDir(mContext, cacheDir);
+    }
     native void rsnContextDump(long con, int bits);
     synchronized void nContextDump(int bits) {
         validate();
@@ -1345,6 +1331,14 @@
         if (rs.mContext == 0) {
             throw new RSDriverException("Failed to create RS context.");
         }
+
+        // set up cache directory for entire context
+        final String CACHE_PATH = "com.android.renderscript.cache";
+        File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
+        String mCachePath = f.getAbsolutePath();
+        f.mkdirs();
+        rs.nContextSetCacheDir(mCachePath);
+
         rs.mMessageThread = new MessageThread(rs);
         rs.mMessageThread.start();
         return rs;
diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java
new file mode 100644
index 0000000..95a9d75
--- /dev/null
+++ b/rs/java/android/renderscript/RenderScriptCacheDir.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008-2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.io.File;
+
+/**
+ * Used only for tracking the RenderScript cache directory.
+ * @hide
+ */
+public class RenderScriptCacheDir {
+     /**
+     * Sets the directory to use as a persistent storage for the
+     * renderscript object file cache.
+     *
+     * @hide
+     * @param cacheDir A directory the current process can write to
+     */
+    public static void setupDiskCache(File cacheDir) {
+        // Defer creation of cache path to nScriptCCreate().
+        mCacheDir = cacheDir;
+    }
+
+    static File mCacheDir;
+
+}
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index 64d21e4..bf706c1 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -124,7 +124,7 @@
 
         // Create the RS cache path if we haven't done so already.
         if (mCachePath == null) {
-            File f = new File(rs.mCacheDir, CACHE_PATH);
+            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
             mCachePath = f.getAbsolutePath();
             f.mkdirs();
         }
@@ -135,7 +135,7 @@
     private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
         // Create the RS cache path if we haven't done so already.
         if (mCachePath == null) {
-            File f = new File(rs.mCacheDir, CACHE_PATH);
+            File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
             mCachePath = f.getAbsolutePath();
             f.mkdirs();
         }
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
index 4a56572..858a957 100644
--- a/rs/java/android/renderscript/ScriptGroup2.java
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -24,26 +24,41 @@
 import java.util.Map;
 
 /**
+ * ScriptGroup2 is a new, enhanced API for script groups.
+ * A script group is a collection of kernels or invocable functions, with
+ * data dependencies defined among them. A script group is launched for
+ * execution as a whole, rather than launching each kernel or invocable function
+ * separately. Once created, a script group can be repeatedly used with
+ * different inputs.
+ * <p>
+ * In the new ScriptGroup2 API, a script group is modeled using closures.
+ * A closure, in this context, is defined as a function call to a kernel or
+ * invocable function. Each function argument or global variable accessed inside
+ * the function is bound to 1) a known value, 2) a script group input, or 3) a
+ * future. A future is the output of a closure, i.e., the return value of the
+ * function or a global variable written by that function.
+ * <p>
+ * A script group is a directed acyclic graph (DAG), in which closures are the
+ * vertices and the dependencies among them are the edges.
+ * The way the ScriptGroup2 API is designed makes cycles impossible in a script
+ * group. For example, it is impossible to make forward references to futures,
+ * i.e., it is impossible to set as input to a closure the future from itself or
+ * a future from another closure that directly or indirectly depends on it.
+ * <p>
+ * Grouping kernels and invocable functions together allows to execute them more
+ * efficiently. Runtime and compiler optimizations are applied to script
+ * groups, to reduce computation or communication overhead, and to make more
+ * efficient use of the CPU and the GPU.
+ */
 
-******************************
-You have tried to change the API from what has been previously approved.
-
-To make these errors go away, you have two choices:
-1) You can add "@hide" javadoc comments to the methods, etc. listed in the
-errors above.
-
-2) You can update current.txt by executing the following command:
-make update-api
-
-To submit the revised current.txt to the main Android repository,
-you will need approval.
-******************************
-
-@hide Pending Android public API approval.
-*/
 public class ScriptGroup2 extends BaseObj {
 
+    /**
+     * An opaque class for closures
+     */
+
     public static class Closure extends BaseObj {
+        private Object[] mArgs;
         private Allocation mReturnValue;
         private Map<Script.FieldID, Object> mBindings;
 
@@ -62,8 +77,9 @@
                        Object[] args, Map<Script.FieldID, Object> globals) {
             super(0, rs);
 
+            mArgs = args;
             mReturnValue = Allocation.createTyped(rs, returnType);
-            mBindings = new HashMap<Script.FieldID, Object>();
+            mBindings = globals;
             mGlobalFuture = new HashMap<Script.FieldID, Future>();
 
             int numValues = args.length + globals.size();
@@ -110,9 +126,10 @@
         public Closure(RenderScript rs, Script.InvokeID invokeID,
                        Object[] args, Map<Script.FieldID, Object> globals) {
             super(0, rs);
-            mFP = FieldPacker.createFieldPack(args);
+            mFP = FieldPacker.createFromArray(args);
 
-            mBindings = new HashMap<Script.FieldID, Object>();
+            mArgs = args;
+            mBindings = globals;
             mGlobalFuture = new HashMap<Script.FieldID, Future>();
 
             int numValues = globals.size();
@@ -132,7 +149,6 @@
                     UnboundValue unbound = (UnboundValue)obj;
                     unbound.addReference(this, fieldID);
                 } else {
-                    // TODO(yangni): Verify obj not a future.
                     retrieveValueAndDependenceInfo(rs, i, obj, values,
                                                    sizes, depClosures, depFieldIDs);
                 }
@@ -174,6 +190,12 @@
             sizes[index] = vs.size;
         }
 
+        /**
+         * Returns the future for the return value
+         *
+         * @return a future
+         */
+
         public Future getReturn() {
             if (mReturnFuture == null) {
                 mReturnFuture = new Future(this, null, mReturnValue);
@@ -182,6 +204,13 @@
             return mReturnFuture;
         }
 
+        /**
+         * Returns the future for a global variable
+         *
+         * @param field the field ID for the global variable
+         * @return a future
+         */
+
         public Future getGlobal(Script.FieldID field) {
             Future f = mGlobalFuture.get(field);
 
@@ -198,11 +227,13 @@
         }
 
         void setArg(int index, Object obj) {
+            mArgs[index] = obj;
             ValueAndSize vs = new ValueAndSize(mRS, obj);
             mRS.nClosureSetArg(getID(mRS), index, vs.value, vs.size);
         }
 
         void setGlobal(Script.FieldID fieldID, Object obj) {
+            mBindings.put(fieldID, obj);
             ValueAndSize vs = new ValueAndSize(mRS, obj);
             mRS.nClosureSetGlobal(getID(mRS), fieldID.getID(mRS), vs.value, vs.size);
         }
@@ -234,6 +265,10 @@
         }
     }
 
+    /**
+     * An opaque class for futures
+     */
+
     public static class Future {
         Closure mClosure;
         Script.FieldID mFieldID;
@@ -250,6 +285,10 @@
         Object getValue() { return mValue; }
     }
 
+    /**
+     * An opaque class for unbound values (a.k.a. script group inputs)
+     */
+
     public static class UnboundValue {
         // Either mFieldID or mArgIndex should be set but not both.
         List<Pair<Closure, Script.FieldID>> mFieldID;
@@ -309,6 +348,13 @@
         setID(id);
     }
 
+    /**
+     * Executes a script group
+     *
+     * @param inputs inputs to the script group
+     * @return outputs of the script group as an array of objects
+     */
+
     public Object[] execute(Object... inputs) {
         if (inputs.length < mInputs.size()) {
             Log.e(TAG, this.toString() + " receives " + inputs.length + " inputs, " +
@@ -343,32 +389,95 @@
     }
 
     /**
-       @hide Pending Android public API approval.
-    */
+     * A class representing a binding of a value to a global variable in a
+     * kernel or invocable function. Such a binding can be used to create a
+     * closure.
+     */
+
     public static final class Binding {
-        public Script.FieldID mField;
-        public Object mValue;
+        private Script.FieldID mField;
+        private Object mValue;
+
+        /**
+         * Returns a Binding object that binds value to field
+         *
+         * @param field the Script.FieldID of the global variable
+         * @param value the value
+         */
+
         public Binding(Script.FieldID field, Object value) {
             mField = field;
             mValue = value;
         }
+
+        /**
+         * Returns the field ID
+         */
+
+        public Script.FieldID getField() { return mField; }
+
+        /**
+         * Returns the value
+         */
+
+        public Object getValue() { return mValue; }
     }
 
     /**
-       @hide Pending Android public API approval.
-    */
+     * The builder class to create a script group.
+     * <p>
+     * Closures are created using the {@link #addKernel} or {@link #addInvoke}
+     * methods.
+     * When a closure is created, futures from previously created closures
+     * can be used as inputs.
+     * Unbound values can be used as inputs to create closures as well.
+     * An unbound value is created using the {@link #addInput} method.
+     * Unbound values become inputs to the script group to be created,
+     * in the order that they are added.
+     * A script group is created by a call to the {@link #create} method, which
+     * accepts an array of futures as the outputs for the script group.
+     * <p>
+     * Closures in a script group can be evaluated in any order as long as the
+     * following conditions are met.
+     * First, a closure must be evaluated before any other closures that take its
+     * futures as inputs.
+     * Second, all closures added before an invoke closure must be evaluated
+     * before it.
+     * Third, all closures added after an invoke closure must be evaluated after
+     * it.
+     * <p>
+     * As a special case, the order that the closures are added is a legal
+     * evaluation order. However, other evaluation orders are allowed, including
+     * concurrently evaluating independent closures.
+     */
+
     public static final class Builder {
         RenderScript mRS;
         List<Closure> mClosures;
         List<UnboundValue> mInputs;
         private static final String TAG = "ScriptGroup2.Builder";
 
+        /**
+         * Returns a Builder object
+         *
+         * @param rs the RenderScript context
+         */
         public Builder(RenderScript rs) {
             mRS = rs;
             mClosures = new ArrayList<Closure>();
             mInputs = new ArrayList<UnboundValue>();
         }
 
+        /**
+         * Adds a closure for a kernel
+         *
+         * @param k Kernel ID for the kernel function
+         * @param returnType Allocation type for the return value
+         * @param args arguments to the kernel function
+         * @param globalBindings bindings for global variables
+         * @return a closure
+         */
+
         public Closure addKernel(Script.KernelID k, Type returnType, Object[] args,
                                  Map<Script.FieldID, Object> globalBindings) {
             Closure c = new Closure(mRS, k, returnType, args, globalBindings);
@@ -376,6 +485,15 @@
             return c;
         }
 
+        /**
+         * Adds a closure for an invocable function
+         *
+         * @param invoke Invoke ID for the invocable function
+         * @param args arguments to the invocable function
+         * @param globalBindings bindings for global variables
+         * @return a closure
+         */
+
         public Closure addInvoke(Script.InvokeID invoke, Object[] args,
                                  Map<Script.FieldID, Object> globalBindings) {
             Closure c = new Closure(mRS, invoke, args, globalBindings);
@@ -383,12 +501,25 @@
             return c;
         }
 
+        /**
+         * Adds a script group input
+         *
+         * @return a unbound value that can be used to create a closure
+         */
         public UnboundValue addInput() {
             UnboundValue unbound = new UnboundValue();
             mInputs.add(unbound);
             return unbound;
         }
 
+        /**
+         * Adds a closure for a kernel
+         *
+         * @param k Kernel ID for the kernel function
+         * @param argsAndBindings arguments followed by bindings for global variables
+         * @return a closure
+         */
+
         public Closure addKernel(Script.KernelID k, Type returnType, Object... argsAndBindings) {
             ArrayList<Object> args = new ArrayList<Object>();
             Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
@@ -398,6 +529,14 @@
             return addKernel(k, returnType, args.toArray(), bindingMap);
         }
 
+        /**
+         * Adds a closure for an invocable function
+         *
+         * @param invoke Invoke ID for the invocable function
+         * @param argsAndBindings arguments followed by bindings for global variables
+         * @return a closure
+         */
+
         public Closure addInvoke(Script.InvokeID invoke, Object... argsAndBindings) {
             ArrayList<Object> args = new ArrayList<Object>();
             Map<Script.FieldID, Object> bindingMap = new HashMap<Script.FieldID, Object>();
@@ -407,7 +546,20 @@
             return addInvoke(invoke, args.toArray(), bindingMap);
         }
 
-        public ScriptGroup2 create(Future... outputs) {
+        /**
+         * Creates a script group
+         *
+         * @param name name for the script group. Legal names can only contain letters, digits,
+         *        '-', or '_'. The name can be no longer than 100 characters.
+         * @param outputs futures intended as outputs of the script group
+         * @return a script group
+         */
+
+        public ScriptGroup2 create(String name, Future... outputs) {
+            if (name == null || name.isEmpty() || name.length() > 100 ||
+                !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
+                throw new RSIllegalArgumentException("invalid script group name");
+            }
             ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
             return ret;
         }
@@ -428,7 +580,7 @@
                     return false;
                 }
                 Binding b = (Binding)argsAndBindings[i];
-                bindingMap.put(b.mField, b.mValue);
+                bindingMap.put(b.getField(), b.getValue());
             }
 
             return true;
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlur.java b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
index 5c4edd3..60e2b6d 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlur.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
@@ -34,7 +34,7 @@
      * Create an intrinsic for applying a blur to an allocation. The
      * default radius is 5.0.
      *
-     * Supported elements types are {@link Element#U8_4}
+     * Supported elements types are {@link Element#U8_4 Element#U8}
      *
      * @param rs The RenderScript context
      * @param e Element type for inputs and outputs
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 886845c..a40233a 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -367,7 +367,7 @@
   return (jlong)(uintptr_t)rsClosureCreate(
       (RsContext)con, (RsScriptKernelID)kernelID, (RsAllocation)returnValue,
       fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
-      (size_t*)sizes, (size_t)sizes_length,
+      (int*)sizes, (size_t)sizes_length,
       depClosures, (size_t)depClosures_length,
       depFieldIDs, (size_t)depFieldIDs_length);
 }
@@ -400,7 +400,7 @@
   return (jlong)(uintptr_t)rsInvokeClosureCreate(
       (RsContext)con, (RsScriptInvokeID)invokeID, jParams, jParamLength,
       fieldIDs, (size_t)fieldIDs_length, values, (size_t)values_length,
-      (size_t*)sizes, (size_t)sizes_length);
+      (int*)sizes, (size_t)sizes_length);
 }
 
 static void
@@ -684,6 +684,17 @@
     rsContextSetPriority((RsContext)con, p);
 }
 
+static void
+nContextSetCacheDir(JNIEnv *_env, jobject _this, jlong con, jstring cacheDir)
+{
+    AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
+
+    if (kLogApi) {
+        ALOGD("ContextSetCacheDir, con(%p), cacheDir(%s)", (RsContext)con, cacheDirUTF.c_str());
+    }
+    rsContextSetCacheDir((RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length());
+}
+
 
 
 static void
@@ -2307,6 +2318,7 @@
 {"rsnContextCreateGL",               "(JIIIIIIIIIIIIFI)J",                    (void*)nContextCreateGL },
 {"rsnContextFinish",                 "(J)V",                                  (void*)nContextFinish },
 {"rsnContextSetPriority",            "(JI)V",                                 (void*)nContextSetPriority },
+{"rsnContextSetCacheDir",            "(JLjava/lang/String;)V",                (void*)nContextSetCacheDir },
 {"rsnContextSetSurface",             "(JIILandroid/view/Surface;)V",          (void*)nContextSetSurface },
 {"rsnContextDestroy",                "(J)V",                                  (void*)nContextDestroy },
 {"rsnContextDump",                   "(JI)V",                                 (void*)nContextDump },
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index da11dad..f42aef1 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -674,7 +674,7 @@
 
     @Override
     public IntentSender createAppWidgetConfigIntentSender(String callingPackage, int appWidgetId,
-            int intentFlags) {
+            final int intentFlags) {
         final int userId = UserHandle.getCallingUserId();
 
         if (DEBUG) {
@@ -701,18 +701,21 @@
                 throw new IllegalArgumentException("Widget not bound " + appWidgetId);
             }
 
+            // Make sure only safe flags can be passed it.
+            final int secureFlags = intentFlags & ~Intent.IMMUTABLE_FLAGS;
+
             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
             intent.setComponent(provider.info.configure);
-            intent.setFlags(intentFlags);
+            intent.setFlags(secureFlags);
 
             // All right, create the sender.
             final long identity = Binder.clearCallingIdentity();
             try {
                 return PendingIntent.getActivityAsUser(
                         mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
-                                | PendingIntent.FLAG_CANCEL_CURRENT, null,
-                                new UserHandle(provider.getUserId()))
+                                | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
+                                null, new UserHandle(provider.getUserId()))
                         .getIntentSender();
             } finally {
                 Binder.restoreCallingIdentity(identity);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 5cc59e5..1bed4f3 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -94,6 +94,7 @@
 import com.android.server.EventLogTags;
 import com.android.server.SystemService;
 import com.android.server.backup.PackageManagerBackupAgent.Metadata;
+import com.android.server.pm.PackageManagerService;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
@@ -2208,7 +2209,10 @@
 
     // Get the restore-set token for the best-available restore set for this package:
     // the active set if possible, else the ancestral one.  Returns zero if none available.
-    long getAvailableRestoreToken(String packageName) {
+    public long getAvailableRestoreToken(String packageName) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+                "getAvailableRestoreToken");
+
         long token = mAncestralToken;
         synchronized (mQueueLock) {
             if (mEverStoredApps.contains(packageName)) {
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 99bbdae..5859c6a 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -317,6 +317,12 @@
     }
 
     @Override
+    public long getAvailableRestoreToken(String packageName) {
+        BackupManagerService svc = mService;
+        return (svc != null) ? svc.getAvailableRestoreToken(packageName) : 0;
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7d156df..34e8b78 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -34,6 +34,7 @@
 import android.os.IBinder;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.Process;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -61,6 +62,7 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Locale;
+import java.util.Random;
 import java.util.TimeZone;
 
 import static android.app.AlarmManager.RTC_WAKEUP;
@@ -128,6 +130,7 @@
     final ResultReceiver mResultReceiver = new ResultReceiver();
     PendingIntent mTimeTickSender;
     PendingIntent mDateChangeSender;
+    Random mRandom;
     boolean mInteractive = true;
     long mNonInteractiveStartTime;
     long mNonInteractiveTime;
@@ -185,18 +188,20 @@
     final class Batch {
         long start;     // These endpoints are always in ELAPSED
         long end;
-        boolean standalone; // certain "batches" don't participate in coalescing
+        int flags;      // Flags for alarms, such as FLAG_STANDALONE.
 
         final ArrayList<Alarm> alarms = new ArrayList<Alarm>();
 
         Batch() {
             start = 0;
             end = Long.MAX_VALUE;
+            flags = 0;
         }
 
         Batch(Alarm seed) {
             start = seed.whenElapsed;
-            end = seed.maxWhen;
+            end = seed.maxWhenElapsed;
+            flags = seed.flags;
             alarms.add(seed);
         }
 
@@ -227,9 +232,10 @@
                 start = alarm.whenElapsed;
                 newStart = true;
             }
-            if (alarm.maxWhen < end) {
-                end = alarm.maxWhen;
+            if (alarm.maxWhenElapsed < end) {
+                end = alarm.maxWhenElapsed;
             }
+            flags |= alarm.flags;
 
             if (DEBUG_BATCH) {
                 Slog.v(TAG, "    => now " + this);
@@ -241,6 +247,7 @@
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
             long newEnd = Long.MAX_VALUE;
+            int newFlags = 0;
             for (int i = 0; i < alarms.size(); ) {
                 Alarm alarm = alarms.get(i);
                 if (alarm.operation.equals(operation)) {
@@ -253,9 +260,10 @@
                     if (alarm.whenElapsed > newStart) {
                         newStart = alarm.whenElapsed;
                     }
-                    if (alarm.maxWhen < newEnd) {
-                        newEnd = alarm.maxWhen;
+                    if (alarm.maxWhenElapsed < newEnd) {
+                        newEnd = alarm.maxWhenElapsed;
                     }
+                    newFlags |= alarm.flags;
                     i++;
                 }
             }
@@ -263,6 +271,7 @@
                 // commit the new batch bounds
                 start = newStart;
                 end = newEnd;
+                flags = newFlags;
             }
             return didRemove;
         }
@@ -271,6 +280,7 @@
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
             long newEnd = Long.MAX_VALUE;
+            int newFlags = 0;
             for (int i = 0; i < alarms.size(); ) {
                 Alarm alarm = alarms.get(i);
                 if (alarm.operation.getTargetPackage().equals(packageName)) {
@@ -283,9 +293,10 @@
                     if (alarm.whenElapsed > newStart) {
                         newStart = alarm.whenElapsed;
                     }
-                    if (alarm.maxWhen < newEnd) {
-                        newEnd = alarm.maxWhen;
+                    if (alarm.maxWhenElapsed < newEnd) {
+                        newEnd = alarm.maxWhenElapsed;
                     }
+                    newFlags |= alarm.flags;
                     i++;
                 }
             }
@@ -293,6 +304,7 @@
                 // commit the new batch bounds
                 start = newStart;
                 end = newEnd;
+                flags = newFlags;
             }
             return didRemove;
         }
@@ -313,8 +325,8 @@
                     if (alarm.whenElapsed > newStart) {
                         newStart = alarm.whenElapsed;
                     }
-                    if (alarm.maxWhen < newEnd) {
-                        newEnd = alarm.maxWhen;
+                    if (alarm.maxWhenElapsed < newEnd) {
+                        newEnd = alarm.maxWhenElapsed;
                     }
                     i++;
                 }
@@ -357,8 +369,9 @@
             b.append(" num="); b.append(size());
             b.append(" start="); b.append(start);
             b.append(" end="); b.append(end);
-            if (standalone) {
-                b.append(" STANDALONE");
+            if (flags != 0) {
+                b.append(" flgs=0x");
+                b.append(Integer.toHexString(flags));
             }
             b.append('}');
             return b.toString();
@@ -441,7 +454,12 @@
     // minimum recurrence period or alarm futurity for us to be able to fuzz it
     static final long MIN_FUZZABLE_INTERVAL = 10000;
     static final BatchTimeOrder sBatchOrder = new BatchTimeOrder();
-    final ArrayList<Batch> mAlarmBatches = new ArrayList<Batch>();
+    final ArrayList<Batch> mAlarmBatches = new ArrayList<>();
+
+    // set to null if in idle mode; while in this mode, any alarms we don't want
+    // to run during this time are placed in mPendingWhileIdleAlarms
+    Alarm mPendingIdleUntil = null;
+    final ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
 
     public AlarmManagerService(Context context) {
         super(context);
@@ -486,7 +504,7 @@
         final int N = mAlarmBatches.size();
         for (int i = 0; i < N; i++) {
             Batch b = mAlarmBatches.get(i);
-            if (!b.standalone && b.canHold(whenElapsed, maxWhen)) {
+            if ((b.flags&AlarmManager.FLAG_STANDALONE) == 0 && b.canHold(whenElapsed, maxWhen)) {
                 return i;
             }
         }
@@ -503,31 +521,56 @@
     void rebatchAllAlarmsLocked(boolean doValidate) {
         ArrayList<Batch> oldSet = (ArrayList<Batch>) mAlarmBatches.clone();
         mAlarmBatches.clear();
+        Alarm oldPendingIdleUntil = mPendingIdleUntil;
         final long nowElapsed = SystemClock.elapsedRealtime();
         final int oldBatches = oldSet.size();
         for (int batchNum = 0; batchNum < oldBatches; batchNum++) {
             Batch batch = oldSet.get(batchNum);
             final int N = batch.size();
             for (int i = 0; i < N; i++) {
-                Alarm a = batch.get(i);
-                long whenElapsed = convertToElapsed(a.when, a.type);
-                final long maxElapsed;
-                if (a.whenElapsed == a.maxWhen) {
-                    // Exact
-                    maxElapsed = whenElapsed;
-                } else {
-                    // Not exact.  Preserve any explicit window, otherwise recalculate
-                    // the window based on the alarm's new futurity.  Note that this
-                    // reflects a policy of preferring timely to deferred delivery.
-                    maxElapsed = (a.windowLength > 0)
-                            ? (whenElapsed + a.windowLength)
-                            : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
-                }
-                setImplLocked(a.type, a.when, whenElapsed, a.windowLength, maxElapsed,
-                        a.repeatInterval, a.operation, batch.standalone, doValidate, a.workSource,
-                        a.alarmClock, a.userId);
+                reAddAlarmLocked(batch.get(i), nowElapsed, doValidate);
             }
         }
+        if (oldPendingIdleUntil != null && oldPendingIdleUntil != mPendingIdleUntil) {
+            Slog.wtf(TAG, "Rebatching: idle until changed from " + oldPendingIdleUntil
+                    + " to " + mPendingIdleUntil);
+            if (mPendingIdleUntil == null) {
+                // Somehow we lost this...  we need to restore all of the pending alarms.
+                restorePendingWhileIdleAlarmsLocked();
+            }
+        }
+        rescheduleKernelAlarmsLocked();
+        updateNextAlarmClockLocked();
+    }
+
+    void reAddAlarmLocked(Alarm a, long nowElapsed, boolean doValidate) {
+        a.when = a.origWhen;
+        long whenElapsed = convertToElapsed(a.when, a.type);
+        final long maxElapsed;
+        if (a.whenElapsed == a.maxWhenElapsed) {
+            // Exact
+            maxElapsed = whenElapsed;
+        } else {
+            // Not exact.  Preserve any explicit window, otherwise recalculate
+            // the window based on the alarm's new futurity.  Note that this
+            // reflects a policy of preferring timely to deferred delivery.
+            maxElapsed = (a.windowLength > 0)
+                    ? (whenElapsed + a.windowLength)
+                    : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval);
+        }
+        a.whenElapsed = whenElapsed;
+        a.maxWhenElapsed = maxElapsed;
+        setImplLocked(a, true, doValidate);
+    }
+
+    void restorePendingWhileIdleAlarmsLocked() {
+        final long nowElapsed = SystemClock.elapsedRealtime();
+        for (int i=mPendingWhileIdleAlarms.size() - 1; i >= 0 && mPendingIdleUntil != null; i --) {
+            Alarm a = mPendingWhileIdleAlarms.remove(i);
+            reAddAlarmLocked(a, nowElapsed, false);
+        }
+        rescheduleKernelAlarmsLocked();
+        updateNextAlarmClockLocked();
     }
 
     static final class InFlight extends Intent {
@@ -687,7 +730,7 @@
     }
 
     void setImpl(int type, long triggerAtTime, long windowLength, long interval,
-            PendingIntent operation, boolean isStandalone, WorkSource workSource,
+            PendingIntent operation, int flags, WorkSource workSource,
             AlarmManager.AlarmClockInfo alarmClock) {
         if (operation == null) {
             Slog.w(TAG, "set/setRepeating ignored because there is no intent");
@@ -745,25 +788,66 @@
                 Slog.v(TAG, "set(" + operation + ") : type=" + type
                         + " triggerAtTime=" + triggerAtTime + " win=" + windowLength
                         + " tElapsed=" + triggerElapsed + " maxElapsed=" + maxElapsed
-                        + " interval=" + interval + " standalone=" + isStandalone);
+                        + " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
             }
             setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
-                    interval, operation, isStandalone, true, workSource, alarmClock, userId);
+                    interval, operation, flags, true, workSource, alarmClock, userId);
         }
     }
 
     private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
-            long maxWhen, long interval, PendingIntent operation, boolean isStandalone,
+            long maxWhen, long interval, PendingIntent operation, int flags,
             boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
             int userId) {
         Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
-                operation, workSource, alarmClock, userId);
+                operation, workSource, flags, alarmClock, userId);
         removeLocked(operation);
+        setImplLocked(a, false, doValidate);
+    }
 
-        int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);
+    private void setImplLocked(Alarm a, boolean rebatching, boolean doValidate) {
+        if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+            // This is a special alarm that will put the system idle until it goes off.
+            // The caller has given the time they want this to happen at, however we need
+            // to pull that earlier if there are existing alarms that have requested to
+            // bring us out of idle.
+            final int N = mAlarmBatches.size();
+            for (int i = 0; i < N; i++) {
+                Batch b = mAlarmBatches.get(i);
+                if (a.whenElapsed > b.end) {
+                    // There are no interesting things happening before our idle until,
+                    // so keep the requested time.
+                    break;
+                }
+                if ((b.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
+                    a.when = a.whenElapsed = a.maxWhenElapsed = b.end;
+                    break;
+                }
+            }
+            // Add fuzz to make the alarm go off some time before the actual desired time.
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            long fuzz = fuzzForDuration(a.whenElapsed-nowElapsed);
+            if (fuzz > 0) {
+                if (mRandom == null) {
+                    mRandom = new Random();
+                }
+                a.whenElapsed -= mRandom.nextLong() % fuzz;
+            }
+
+        } else if (mPendingIdleUntil != null) {
+            // We currently have an idle until alarm scheduled; if the new alarm has
+            // not explicitly stated it wants to run while idle, then put it on hold.
+            if ((a.flags&(AlarmManager.FLAG_ALLOW_WHILE_IDLE|AlarmManager.FLAG_WAKE_FROM_IDLE))
+                    == 0) {
+                mPendingWhileIdleAlarms.add(a);
+                return;
+            }
+        }
+
+        int whichBatch = ((a.flags&AlarmManager.FLAG_STANDALONE) != 0)
+                ? -1 : attemptCoalesceLocked(a.whenElapsed, a.maxWhenElapsed);
         if (whichBatch < 0) {
             Batch batch = new Batch(a);
-            batch.standalone = isStandalone;
             addBatchLocked(mAlarmBatches, batch);
         } else {
             Batch batch = mAlarmBatches.get(whichBatch);
@@ -775,28 +859,48 @@
             }
         }
 
-        if (alarmClock != null) {
+        if (a.alarmClock != null) {
             mNextAlarmClockMayChange = true;
-            updateNextAlarmClockLocked();
         }
 
-        if (DEBUG_VALIDATE) {
-            if (doValidate && !validateConsistencyLocked()) {
-                Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when
-                        + " when(hex)=" + Long.toHexString(when)
-                        + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen
-                        + " interval=" + interval + " op=" + operation
-                        + " standalone=" + isStandalone);
+        boolean needRebatch = false;
+
+        if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+            mPendingIdleUntil = a;
+            needRebatch = true;
+        } else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0 && mPendingIdleUntil != null) {
+            // If we are adding an alarm that asks to wake from idle, and we are currently
+            // idling, then we need to rebatch alarms in case the idle until time needs to
+            // be updated.
+            needRebatch = true;
+        }
+
+        if (!rebatching) {
+            if (DEBUG_VALIDATE) {
+                if (doValidate && !validateConsistencyLocked()) {
+                    Slog.v(TAG, "Tipping-point operation: type=" + a.type + " when=" + a.when
+                            + " when(hex)=" + Long.toHexString(a.when)
+                            + " whenElapsed=" + a.whenElapsed
+                            + " maxWhenElapsed=" + a.maxWhenElapsed
+                            + " interval=" + a.repeatInterval + " op=" + a.operation
+                            + " flags=0x" + Integer.toHexString(a.flags));
+                    rebatchAllAlarmsLocked(false);
+                    needRebatch = false;
+                }
+            }
+
+            if (needRebatch) {
                 rebatchAllAlarmsLocked(false);
             }
-        }
 
-        rescheduleKernelAlarmsLocked();
+            rescheduleKernelAlarmsLocked();
+            updateNextAlarmClockLocked();
+        }
     }
 
     private final IBinder mService = new IAlarmManager.Stub() {
         @Override
-        public void set(int type, long triggerAtTime, long windowLength, long interval,
+        public void set(int type, long triggerAtTime, long windowLength, long interval, int flags,
                 PendingIntent operation, WorkSource workSource,
                 AlarmManager.AlarmClockInfo alarmClock) {
             if (workSource != null) {
@@ -805,8 +909,17 @@
                         "AlarmManager.set");
             }
 
+            if (windowLength == AlarmManager.WINDOW_EXACT) {
+                flags |= AlarmManager.FLAG_STANDALONE;
+            }
+            if (alarmClock != null) {
+                flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
+            }
+            if (Binder.getCallingUid() < Process.FIRST_APPLICATION_UID) {
+                flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE;
+            }
             setImpl(type, triggerAtTime, windowLength, interval, operation,
-                    windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
+                    flags, workSource, alarmClock);
         }
 
         @Override
@@ -912,6 +1025,14 @@
                     dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC, sdf);
                 }
             }
+            if (mPendingIdleUntil != null) {
+                pw.println();
+                pw.println("Idle mode state:");
+                pw.print("  Idling until: "); pw.println(mPendingIdleUntil);
+                mPendingIdleUntil.dump(pw, "    ", nowELAPSED, nowRTC, sdf);
+                pw.println("  Pending alarms:");
+                dumpAlarmList(pw, mPendingWhileIdleAlarms, "    ", nowELAPSED, nowRTC, sdf);
+            }
 
             pw.println();
             pw.print("Past-due non-wakeup alarms: ");
@@ -1224,6 +1345,15 @@
     }
 
     void rescheduleKernelAlarmsLocked() {
+        if (mPendingIdleUntil != null) {
+            // If we have a pending "idle until" alarm, we will just blindly wait until
+            // it is time for that alarm to go off.  We don't want to wake up for any
+            // other reasons.
+            mNextWakeup = mNextNonWakeup = mPendingIdleUntil.whenElapsed;
+            setLocked(ELAPSED_REALTIME_WAKEUP, mNextWakeup);
+            setLocked(ELAPSED_REALTIME, mNextNonWakeup);
+            return;
+        }
         // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
         // prior to that which contains no wakeups, we schedule that as well.
         long nextNonWakeup = 0;
@@ -1260,13 +1390,26 @@
                 mAlarmBatches.remove(i);
             }
         }
+        for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
+            if (mPendingWhileIdleAlarms.get(i).operation.equals(operation)) {
+                // Don't set didRemove, since this doesn't impact the scheduled alarms.
+                mPendingWhileIdleAlarms.remove(i);
+            }
+        }
 
         if (didRemove) {
             if (DEBUG_BATCH) {
                 Slog.v(TAG, "remove(operation) changed bounds; rebatching");
             }
+            boolean restorePending = false;
+            if (mPendingIdleUntil != null && mPendingIdleUntil.operation.equals(operation)) {
+                mPendingIdleUntil = null;
+                restorePending = true;
+            }
             rebatchAllAlarmsLocked(true);
-            rescheduleKernelAlarmsLocked();
+            if (restorePending) {
+                restorePendingWhileIdleAlarmsLocked();
+            }
             updateNextAlarmClockLocked();
         }
     }
@@ -1280,6 +1423,12 @@
                 mAlarmBatches.remove(i);
             }
         }
+        for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
+            if (mPendingWhileIdleAlarms.get(i).operation.getTargetPackage().equals(packageName)) {
+                // Don't set didRemove, since this doesn't impact the scheduled alarms.
+                mPendingWhileIdleAlarms.remove(i);
+            }
+        }
 
         if (didRemove) {
             if (DEBUG_BATCH) {
@@ -1300,6 +1449,13 @@
                 mAlarmBatches.remove(i);
             }
         }
+        for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
+            if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).operation.getCreatorUid())
+                    == userHandle) {
+                // Don't set didRemove, since this doesn't impact the scheduled alarms.
+                mPendingWhileIdleAlarms.remove(i);
+            }
+        }
 
         if (didRemove) {
             if (DEBUG_BATCH) {
@@ -1344,6 +1500,11 @@
                 return true;
             }
         }
+        for (int i = 0; i < mPendingWhileIdleAlarms.size(); i++) {
+            if (mPendingWhileIdleAlarms.get(i).operation.getTargetPackage().equals(packageName)) {
+                return true;
+            }
+        }
         return false;
     }
 
@@ -1413,6 +1574,13 @@
     boolean triggerAlarmsLocked(ArrayList<Alarm> triggerList, final long nowELAPSED,
             final long nowRTC) {
         boolean hasWakeup = false;
+        if (mPendingIdleUntil != null) {
+            // If we have a pending "idle until" alarm, don't trigger any alarms
+            // until we are past the idle period.
+            if (nowELAPSED < mPendingIdleUntil.whenElapsed) {
+                return false;
+            }
+        }
         // batches are temporally sorted, so we need only pull from the
         // start of the list until we either empty it or hit a batch
         // that is not yet deliverable
@@ -1432,6 +1600,11 @@
                 Alarm alarm = batch.get(i);
                 alarm.count = 1;
                 triggerList.add(alarm);
+                if (mPendingIdleUntil == alarm) {
+                    mPendingIdleUntil = null;
+                    rebatchAllAlarmsLocked(false);
+                    restorePendingWhileIdleAlarmsLocked();
+                }
 
                 // Recurring alarms may have passed several alarm intervals while the
                 // phone was asleep or off, so pass a trigger count when sending them.
@@ -1445,7 +1618,7 @@
                     final long nextElapsed = alarm.whenElapsed + delta;
                     setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
                             maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
-                            alarm.repeatInterval, alarm.operation, batch.standalone, true,
+                            alarm.repeatInterval, alarm.operation, alarm.flags, true,
                             alarm.workSource, alarm.alarmClock, alarm.userId);
                 }
 
@@ -1494,34 +1667,38 @@
     
     private static class Alarm {
         public final int type;
+        public final long origWhen;
         public final boolean wakeup;
         public final PendingIntent operation;
         public final String  tag;
         public final WorkSource workSource;
+        public final int flags;
         public int count;
         public long when;
         public long windowLength;
         public long whenElapsed;    // 'when' in the elapsed time base
-        public long maxWhen;        // also in the elapsed time base
+        public long maxWhenElapsed; // also in the elapsed time base
         public long repeatInterval;
         public final AlarmManager.AlarmClockInfo alarmClock;
         public final int userId;
         public PriorityClass priorityClass;
 
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
-                long _interval, PendingIntent _op, WorkSource _ws,
+                long _interval, PendingIntent _op, WorkSource _ws, int _flags,
                 AlarmManager.AlarmClockInfo _info, int _userId) {
             type = _type;
+            origWhen = _when;
             wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
                     || _type == AlarmManager.RTC_WAKEUP;
             when = _when;
             whenElapsed = _whenElapsed;
             windowLength = _windowLength;
-            maxWhen = _maxWhen;
+            maxWhenElapsed = _maxWhen;
             repeatInterval = _interval;
             operation = _op;
             tag = makeTag(_op, _type);
             workSource = _ws;
+            flags = _flags;
             alarmClock = _info;
             userId = _userId;
         }
@@ -1561,7 +1738,8 @@
                     pw.println();
             pw.print(prefix); pw.print("window="); pw.print(windowLength);
                     pw.print(" repeatInterval="); pw.print(repeatInterval);
-                    pw.print(" count="); pw.println(count);
+                    pw.print(" count="); pw.print(count);
+                    pw.print(" flags=0x"); pw.println(Integer.toHexString(flags));
             pw.print(prefix); pw.print("operation="); pw.println(operation);
         }
     }
@@ -1599,6 +1777,20 @@
         }
     }
 
+    static long fuzzForDuration(long duration) {
+        if (duration < 15*60*1000) {
+            // If the duration until the time is less than 15 minutes, the maximum fuzz
+            // is the duration.
+            return duration;
+        } else if (duration < 90*60*1000) {
+            // If duration is less than 1 1/2 hours, the maximum fuzz is 15 minutes,
+            return 15*60*1000;
+        } else {
+            // Otherwise, we will fuzz by at most half an hour.
+            return 30*60*1000;
+        }
+    }
+
     boolean checkAllowNonWakeupDelayLocked(long nowELAPSED) {
         if (mInteractive) {
             return false;
@@ -1886,7 +2078,7 @@
 
             final WorkSource workSource = null; // Let system take blame for time tick events.
             setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
-                    0, mTimeTickSender, true, workSource, null);
+                    0, mTimeTickSender, AlarmManager.FLAG_STANDALONE, workSource, null);
         }
 
         public void scheduleDateChangedEvent() {
@@ -1899,8 +2091,8 @@
             calendar.add(Calendar.DAY_OF_MONTH, 1);
 
             final WorkSource workSource = null; // Let system take blame for date change events.
-            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, true, workSource,
-                    null);
+            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender,
+                    AlarmManager.FLAG_STANDALONE, workSource, null);
         }
     }
     
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index e6dc1c7..66cc29a 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -403,24 +403,32 @@
         if (cpuCount == 1) {
             new ComputeWorker(MIN_SIZE, MAX_SIZE, STEP, bitmaps, pixelCount, results, null).run();
         } else {
-            int start = MIN_SIZE;
-            int end = MAX_SIZE - (cpuCount - 1) * STEP;
+            int start = MIN_SIZE + (cpuCount - 1) * STEP;
+            int end = MAX_SIZE;
             int step = STEP * cpuCount;
 
             final CountDownLatch signal = new CountDownLatch(cpuCount);
 
-            for (int i = 0; i < cpuCount; i++, start += STEP, end += STEP) {
+            for (int i = 0; i < cpuCount; i++, start -= STEP, end -= STEP) {
                 ComputeWorker worker = new ComputeWorker(start, end, step,
                         bitmaps, pixelCount, results, signal);
                 new Thread(worker, "Atlas Worker #" + (i + 1)).start();
             }
 
+            boolean isAllWorkerFinished;
             try {
-                signal.await(10, TimeUnit.SECONDS);
+                isAllWorkerFinished = signal.await(10, TimeUnit.SECONDS);
             } catch (InterruptedException e) {
                 Log.w(LOG_TAG, "Could not complete configuration computation");
                 return null;
             }
+
+            if (!isAllWorkerFinished) {
+                // We have to abort here, otherwise the async updates on "results" would crash the
+                // sort later.
+                Log.w(LOG_TAG, "Could not complete configuration computation before timeout.");
+                return null;
+            }
         }
 
         // Maximize the number of packed bitmaps, minimize the texture size
@@ -435,7 +443,8 @@
 
         if (DEBUG_ATLAS) {
             float delay = (System.nanoTime() - begin) / 1000.0f / 1000.0f / 1000.0f;
-            Log.d(LOG_TAG, String.format("Found best atlas configuration in %.2fs", delay));
+            Log.d(LOG_TAG, String.format("Found best atlas configuration (out of %d) in %.2fs",
+                    results.size(), delay));
         }
 
         WorkerResult result = results.get(0);
@@ -696,8 +705,8 @@
 
             Atlas.Entry entry = new Atlas.Entry();
             for (Atlas.Type type : Atlas.Type.values()) {
-                for (int width = mStart; width < mEnd; width += mStep) {
-                    for (int height = MIN_SIZE; height < MAX_SIZE; height += STEP) {
+                for (int width = mEnd; width > mStart; width -= mStep) {
+                    for (int height = MAX_SIZE; height > MIN_SIZE; height -= STEP) {
                         // If the atlas is not big enough, skip it
                         if (width * height <= mThreshold) continue;
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 201c755..1ac1c8a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1487,7 +1487,7 @@
                 NetworkCapabilities.TRANSPORT_WIFI)) {
             timeout = Settings.Global.getInt(mContext.getContentResolver(),
                                              Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI,
-                                             0);
+                                             5);
             type = ConnectivityManager.TYPE_WIFI;
         } else {
             // do not track any other networks
@@ -2023,6 +2023,8 @@
                         ReapUnvalidatedNetworks.DONT_REAP);
             }
         }
+        NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo);
+        if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name);
     }
 
     // If this method proves to be too slow then we can maintain a separate
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4677f65..d92a89f 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -15,6 +15,7 @@
 
 package com.android.server;
 
+import android.annotation.NonNull;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -1285,13 +1286,24 @@
         return startInputUncheckedLocked(cs, inputContext, attribute, controlFlags);
     }
 
-    InputBindResult startInputUncheckedLocked(ClientState cs,
+    InputBindResult startInputUncheckedLocked(@NonNull ClientState cs,
             IInputContext inputContext, EditorInfo attribute, int controlFlags) {
         // If no method is currently selected, do nothing.
         if (mCurMethodId == null) {
             return mNoBinding;
         }
 
+        if (attribute != null) {
+            // We accept an empty package name as a valid data.
+            if (!TextUtils.isEmpty(attribute.packageName) &&
+                    !InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, cs.uid,
+                            attribute.packageName)) {
+                Slog.e(TAG, "Rejecting this client as it reported an invalid package name."
+                        + " uid=" + cs.uid + " package=" + attribute.packageName);
+                return mNoBinding;
+            }
+        }
+
         if (mCurClient != cs) {
             // Was the keyguard locked when switching over to the new client?
             mCurClientInKeyguard = isKeyguardLocked();
@@ -1855,16 +1867,10 @@
         }
 
         if (mCurClient != null && mCurAttribute != null) {
-            final int uid = mCurClient.uid;
-            final String packageName = mCurAttribute.packageName;
-            if (SystemConfig.getInstance().getFixedImeApps().contains(packageName)) {
-                if (InputMethodUtils.checkIfPackageBelongsToUid(mAppOpsManager, uid, packageName)) {
-                    return;
-                }
-                // TODO: Do we need to lock the input method when the application reported an
-                // incorrect package name?
-                Slog.e(TAG, "Ignoring FixedImeApps due to the validation failure. uid=" + uid
-                        + " package=" + packageName);
+            // We have already made sure that the package name belongs to the application's UID.
+            // No further UID check is required.
+            if (SystemConfig.getInstance().getFixedImeApps().contains(mCurAttribute.packageName)) {
+                return;
             }
         }
 
@@ -2148,7 +2154,7 @@
                 // more quickly (not get stuck behind it initializing itself for the
                 // new focused input, even if its window wants to hide the IME).
                 boolean didStart = false;
-                        
+
                 switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
                     case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
                         if (!isTextEditor || !doAutoShow) {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 0de6a03..9409615 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -36,6 +36,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.service.carrier.CarrierMessagingService;
+import android.telephony.SmsManager;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
 
@@ -111,6 +112,106 @@
         }
     };
 
+    // Instance of IMms for returning failure to service API caller,
+    // used when MmsService cannot be connected.
+    private final IMms mServiceStubForFailure = new IMms() {
+
+        @Override
+        public IBinder asBinder() {
+            return null;
+        }
+
+        @Override
+        public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl,
+                Bundle configOverrides, PendingIntent sentIntent) throws RemoteException {
+            returnPendingIntentWithError(sentIntent);
+        }
+
+        @Override
+        public void downloadMessage(int subId, String callingPkg, String locationUrl,
+                Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent)
+                throws RemoteException {
+            returnPendingIntentWithError(downloadedIntent);
+        }
+
+        @Override
+        public Bundle getCarrierConfigValues(int subId) throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public Uri importTextMessage(String callingPkg, String address, int type, String text,
+                long timestampMillis, boolean seen, boolean read) throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public Uri importMultimediaMessage(String callingPkg, Uri contentUri, String messageId,
+                long timestampSecs, boolean seen, boolean read) throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public boolean deleteStoredMessage(String callingPkg, Uri messageUri)
+                throws RemoteException {
+            return false;
+        }
+
+        @Override
+        public boolean deleteStoredConversation(String callingPkg, long conversationId)
+                throws RemoteException {
+            return false;
+        }
+
+        @Override
+        public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri,
+                ContentValues statusValues) throws RemoteException {
+            return false;
+        }
+
+        @Override
+        public boolean archiveStoredConversation(String callingPkg, long conversationId,
+                boolean archived) throws RemoteException {
+            return false;
+        }
+
+        @Override
+        public Uri addTextMessageDraft(String callingPkg, String address, String text)
+                throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri)
+                throws RemoteException {
+            return null;
+        }
+
+        @Override
+        public void sendStoredMessage(int subId, String callingPkg, Uri messageUri,
+                Bundle configOverrides, PendingIntent sentIntent) throws RemoteException {
+            returnPendingIntentWithError(sentIntent);
+        }
+
+        @Override
+        public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException {
+            // Do nothing
+        }
+
+        @Override
+        public boolean getAutoPersisting() throws RemoteException {
+            return false;
+        }
+
+        private void returnPendingIntentWithError(PendingIntent pendingIntent) {
+            try {
+                pendingIntent.send(mContext, SmsManager.MMS_ERROR_UNSPECIFIED, null);
+            } catch (PendingIntent.CanceledException e) {
+                Slog.e(TAG, "Failed to return pending intent result", e);
+            }
+        }
+    };
+
     public MmsServiceBroker(Context context) {
         super(context);
         mContext = context;
@@ -145,44 +246,51 @@
         }
     }
 
-    private void ensureService() {
+    private IMms getOrConnectService() {
         synchronized (this) {
-            if (mService == null) {
-                // Service is not connected. Try blocking connecting.
-                Slog.w(TAG, "MmsService not connected. Try connecting...");
-                mConnectionHandler.sendMessage(
-                        mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
-                final long shouldEnd =
-                        SystemClock.elapsedRealtime() + SERVICE_CONNECTION_WAIT_TIME_MS;
-                long waitTime = SERVICE_CONNECTION_WAIT_TIME_MS;
-                while (waitTime > 0) {
-                    try {
-                        // TODO: consider using Java concurrent construct instead of raw object wait
-                        this.wait(waitTime);
-                    } catch (InterruptedException e) {
-                        Slog.w(TAG, "Connection wait interrupted", e);
-                    }
-                    if (mService != null) {
-                        // Success
-                        return;
-                    }
-                    // Calculate remaining waiting time to make sure we wait the full timeout period
-                    waitTime = shouldEnd - SystemClock.elapsedRealtime();
-                }
-                // Timed out. Something's really wrong.
-                Slog.e(TAG, "Can not connect to MmsService (timed out)");
-                throw new RuntimeException("Timed out in connecting to MmsService");
+            if (mService != null) {
+                return mService;
             }
+            // Service is not connected. Try blocking connecting.
+            Slog.w(TAG, "MmsService not connected. Try connecting...");
+            mConnectionHandler.sendMessage(
+                    mConnectionHandler.obtainMessage(MSG_TRY_CONNECTING));
+            final long shouldEnd =
+                    SystemClock.elapsedRealtime() + SERVICE_CONNECTION_WAIT_TIME_MS;
+            long waitTime = SERVICE_CONNECTION_WAIT_TIME_MS;
+            while (waitTime > 0) {
+                try {
+                    // TODO: consider using Java concurrent construct instead of raw object wait
+                    this.wait(waitTime);
+                } catch (InterruptedException e) {
+                    Slog.w(TAG, "Connection wait interrupted", e);
+                }
+                if (mService != null) {
+                    // Success
+                    return mService;
+                }
+                // Calculate remaining waiting time to make sure we wait the full timeout period
+                waitTime = shouldEnd - SystemClock.elapsedRealtime();
+            }
+            // Timed out. Something's really wrong.
+            Slog.e(TAG, "Can not connect to MmsService (timed out)");
+            return null;
         }
     }
 
     /**
-     * Making sure when we obtain the mService instance it is always valid.
-     * Throws {@link RuntimeException} when it is empty.
+     * Make sure to return a non-empty service instance. Return the connected MmsService
+     * instance, if not connected, try connecting. If fail to connect, return a fake service
+     * instance which returns failure to service caller.
+     *
+     * @return a non-empty service instance, real or fake
      */
     private IMms getServiceGuarded() {
-        ensureService();
-        return mService;
+        final IMms service = getOrConnectService();
+        if (service != null) {
+            return service;
+        }
+        return mServiceStubForFailure;
     }
 
     private AppOpsManager getAppOpsManager() {
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 61286e8..a341c95 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -36,12 +36,14 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.DiskInfo;
 import android.os.storage.IMountService;
 import android.os.storage.IMountServiceListener;
 import android.os.storage.IMountShutdownObserver;
@@ -50,11 +52,11 @@
 import android.os.storage.StorageManager;
 import android.os.storage.StorageResultCode;
 import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
-import android.util.DebugUtils;
+import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
 
 import libcore.util.EmptyArray;
 import libcore.util.HexEncoding;
@@ -62,13 +64,13 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IMediaContainerService;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
 import com.android.server.NativeDaemonConnector.Command;
 import com.android.server.NativeDaemonConnector.SensitiveArg;
 import com.android.server.pm.PackageManagerService;
-import com.google.android.collect.Lists;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -91,6 +93,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -143,7 +146,6 @@
     }
 
     private static final boolean LOCAL_LOGD = false;
-    private static final boolean DEBUG_UNMOUNT = false;
     private static final boolean DEBUG_EVENTS = false;
     private static final boolean DEBUG_OBB = false;
 
@@ -157,8 +159,6 @@
     /** Maximum number of ASEC containers allowed to be mounted. */
     private static final int MAX_CONTAINERS = 250;
 
-    private static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
-
     /*
      * Internal vold response code constants
      */
@@ -213,22 +213,6 @@
         public static final int FstrimCompleted                = 700;
     }
 
-    private static SparseArray<String> sStateToEnvironment = new SparseArray<>();
-    private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>();
-
-    static {
-        sStateToEnvironment.put(Volume.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED);
-        sStateToEnvironment.put(Volume.STATE_MOUNTING, Environment.MEDIA_CHECKING);
-        sStateToEnvironment.put(Volume.STATE_MOUNTED, Environment.MEDIA_MOUNTED);
-        sStateToEnvironment.put(Volume.STATE_FORMATTING, Environment.MEDIA_UNMOUNTED);
-        sStateToEnvironment.put(Volume.STATE_UNMOUNTING, Environment.MEDIA_EJECTING);
-
-        sEnvironmentToBroadcast.put(Environment.MEDIA_UNMOUNTED, Intent.ACTION_MEDIA_UNMOUNTED);
-        sEnvironmentToBroadcast.put(Environment.MEDIA_CHECKING, Intent.ACTION_MEDIA_CHECKING);
-        sEnvironmentToBroadcast.put(Environment.MEDIA_MOUNTED, Intent.ACTION_MEDIA_MOUNTED);
-        sEnvironmentToBroadcast.put(Environment.MEDIA_EJECTING, Intent.ACTION_MEDIA_EJECT);
-    }
-
     /**
      * <em>Never</em> hold the lock while performing downcalls into vold, since
      * unsolicited events can suddenly appear to update data structures.
@@ -238,215 +222,50 @@
     @GuardedBy("mLock")
     private int[] mStartedUsers = EmptyArray.INT;
     @GuardedBy("mLock")
-    private ArrayMap<String, Disk> mDisks = new ArrayMap<>();
+    private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
     @GuardedBy("mLock")
-    private ArrayMap<String, Volume> mVolumes = new ArrayMap<>();
+    private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
+
+    private DiskInfo findDiskById(String id) {
+        synchronized (mLock) {
+            final DiskInfo disk = mDisks.get(id);
+            if (disk != null) {
+                return disk;
+            }
+        }
+        throw new IllegalArgumentException("No disk found for ID " + id);
+    }
+
+    private VolumeInfo findVolumeById(String id) {
+        synchronized (mLock) {
+            final VolumeInfo vol = mVolumes.get(id);
+            if (vol != null) {
+                return vol;
+            }
+        }
+        throw new IllegalArgumentException("No volume found for ID " + id);
+    }
 
     @Deprecated
-    private Volume findVolumeByLegacyPath(String legacyPath) {
+    private String findVolumeIdForPath(String path) {
         synchronized (mLock) {
-            for (Volume vol : mVolumes.values()) {
-                if (vol.path != null && legacyPath.startsWith(vol.path)) {
-                    return vol;
+            for (int i = 0; i < mVolumes.size(); i++) {
+                final VolumeInfo vol = mVolumes.valueAt(i);
+                if (vol.path != null && path.startsWith(vol.path)) {
+                    return vol.id;
                 }
             }
         }
-        Slog.w(TAG, "Failed to find volume for path " + legacyPath);
-        return null;
-    }
-
-    /**
-     * Framework-side twin of android::vold::Disk
-     */
-    private class Disk {
-        public static final int FLAG_ADOPTABLE = 1 << 0;
-        public static final int FLAG_DEFAULT_PRIMARY = 1 << 1;
-        public static final int FLAG_SD = 1 << 2;
-        public static final int FLAG_USB = 1 << 3;
-
-        public final String id;
-        public final int flags;
-        public long size;
-        public String label;
-
-        public ArrayList<Volume> volumes = new ArrayList<>();
-
-        public Disk(String id, int flags) {
-            this.id = id;
-            this.flags = flags;
-        }
-
-        public void partitionPublic() throws NativeDaemonConnectorException {
-            mConnector.execute("volume", "partition", id, "public");
-        }
-
-        public void partitionPrivate() throws NativeDaemonConnectorException {
-            mConnector.execute("volume", "partition", id, "private");
-        }
-
-        public void partitionMixed(int frac) throws NativeDaemonConnectorException {
-            mConnector.execute("volume", "partition", id, "mixed", frac);
-        }
-
-        public void dump(IndentingPrintWriter pw) {
-            pw.println("Disk:");
-            pw.increaseIndent();
-            pw.printPair("id", id);
-            pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
-            pw.printPair("size", size);
-            pw.printPair("label", label);
-            pw.decreaseIndent();
-            pw.println();
-        }
+        throw new IllegalArgumentException("No volume found for path " + path);
     }
 
     private static int sNextMtpIndex = 1;
 
-    /**
-     * Framework-side twin of android::vold::VolumeBase
-     */
-    private class Volume {
-        public static final String ID_EMULATED_INTERNAL = "emulated";
-
-        public static final int TYPE_PUBLIC = 0;
-        public static final int TYPE_PRIVATE = 1;
-        public static final int TYPE_EMULATED = 2;
-        public static final int TYPE_ASEC = 3;
-        public static final int TYPE_OBB = 4;
-
-        public static final int STATE_UNMOUNTED = 0;
-        public static final int STATE_MOUNTING = 1;
-        public static final int STATE_MOUNTED = 2;
-        public static final int STATE_FORMATTING = 3;
-        public static final int STATE_UNMOUNTING = 4;
-
-        public static final int FLAG_PRIMARY = 1 << 0;
-        public static final int FLAG_VISIBLE = 1 << 1;
-
-        /** vold state */
-        public final String id;
-        public final int type;
-        public int flags = 0;
-        public int userId = -1;
-        public int state = STATE_UNMOUNTED;
-        public String fsType;
-        public String fsUuid;
-        public String fsLabel;
-        public String path = "/dev/null";
-
-        /** Framework state */
-        public final int mtpIndex;
-
-        public Disk disk;
-
-        public Volume(String id, int type) {
-            this.id = id;
-            this.type = type;
-
-            if (ID_EMULATED_INTERNAL.equals(id)) {
-                mtpIndex = 0;
-            } else {
-                mtpIndex = sNextMtpIndex++;
-            }
-        }
-
-        public boolean isPrimary() {
-            return (flags & FLAG_PRIMARY) != 0;
-        }
-
-        public boolean isVisible() {
-            return (flags & FLAG_VISIBLE) != 0;
-        }
-
-        public boolean isVisibleToUser(int userId) {
-            if (type == TYPE_PUBLIC && this.userId == userId) {
-                return isVisible();
-            } else if (type == TYPE_EMULATED) {
-                return isVisible();
-            } else {
-                return false;
-            }
-        }
-
-        public void mount() throws NativeDaemonConnectorException {
-            mConnector.execute("volume", "mount", id, flags, userId);
-        }
-
-        public void unmount() throws NativeDaemonConnectorException {
-            mConnector.execute("volume", "unmount", id);
-        }
-
-        public void format() throws NativeDaemonConnectorException {
-            mConnector.execute("volume", "format", id);
-        }
-
-        public StorageVolume buildVolumeForUser(int userId) {
-            final File userPath;
-            final boolean removable;
-            final boolean emulated;
-            final boolean allowMassStorage = false;
-            final int mtpStorageId = MtpStorage.getStorageIdForIndex(mtpIndex);
-            final String envState = sStateToEnvironment.get(state);
-
-            int descriptionId = com.android.internal.R.string.unknownName;
-            long mtpReserveSize = 0;
-            long maxFileSize = 0;
-
-            if (type == TYPE_EMULATED) {
-                userPath = new File(path, Integer.toString(userId));
-                emulated = true;
-                mtpReserveSize = StorageManager.from(mContext).getStorageLowBytes(userPath);
-                descriptionId = com.android.internal.R.string.storage_internal;
-
-                if (ID_EMULATED_INTERNAL.equals(id)) {
-                    removable = false;
-                } else {
-                    removable = true;
-                }
-
-            } else if (type == TYPE_PUBLIC) {
-                userPath = new File(path);
-                emulated = false;
-                removable = true;
-
-                if (disk != null) {
-                    if ((disk.flags & Disk.FLAG_SD) != 0) {
-                        descriptionId = com.android.internal.R.string.storage_sd_card;
-                    } else if ((disk.flags & Disk.FLAG_USB) != 0) {
-                        descriptionId = com.android.internal.R.string.storage_usb;
-                    }
-                }
-
-                if ("vfat".equals(fsType)) {
-                    maxFileSize = 4294967295L;
-                }
-
-            } else {
-                throw new IllegalStateException("Unexpected volume type " + type);
-            }
-
-            return new StorageVolume(id, mtpStorageId, userPath, descriptionId, isPrimary(),
-                    removable, emulated, mtpReserveSize, allowMassStorage, maxFileSize,
-                    new UserHandle(userId), fsUuid, fsLabel, envState);
-        }
-
-        public void dump(IndentingPrintWriter pw) {
-            pw.println("Volume:");
-            pw.increaseIndent();
-            pw.printPair("id", id);
-            pw.printPair("type", DebugUtils.valueToString(getClass(), "TYPE_", type));
-            pw.printPair("flags", DebugUtils.flagsToString(getClass(), "FLAG_", flags));
-            pw.printPair("userId", userId);
-            pw.printPair("state", DebugUtils.valueToString(getClass(), "STATE_", state));
-            pw.println();
-            pw.printPair("fsType", fsType);
-            pw.printPair("fsUuid", fsUuid);
-            pw.printPair("fsLabel", fsLabel);
-            pw.println();
-            pw.printPair("path", path);
-            pw.printPair("mtpIndex", mtpIndex);
-            pw.decreaseIndent();
-            pw.println();
+    private static int allocateMtpIndex(String volId) {
+        if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volId)) {
+            return 0;
+        } else {
+            return sNextMtpIndex++;
         }
     }
 
@@ -462,10 +281,9 @@
     private volatile boolean mSystemReady = false;
     private volatile boolean mDaemonConnected = false;
 
-    private PackageManagerService                 mPms;
-    // Used as a lock for methods that register/unregister listeners.
-    final private ArrayList<MountServiceBinderListener> mListeners =
-            new ArrayList<MountServiceBinderListener>();
+    private PackageManagerService mPms;
+
+    private final Callbacks mCallbacks;
 
     private final CountDownLatch mConnectedSignal = new CountDownLatch(1);
     private final CountDownLatch mAsecsScanned = new CountDownLatch(1);
@@ -672,20 +490,20 @@
                     break;
                 }
                 case H_VOLUME_MOUNT: {
-                    final Volume vol = (Volume) msg.obj;
+                    final VolumeInfo vol = (VolumeInfo) msg.obj;
                     try {
-                        vol.mount();
+                        mConnector.execute("volume", "mount", vol.id, vol.flags, vol.userId);
                     } catch (NativeDaemonConnectorException ignored) {
                     }
                     break;
                 }
                 case H_VOLUME_BROADCAST: {
                     final StorageVolume userVol = (StorageVolume) msg.obj;
-                    final String state = userVol.getState();
-                    Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + state + " to "
+                    final String envState = userVol.getState();
+                    Slog.d(TAG, "Volume " + userVol.getId() + " broadcasting " + envState + " to "
                             + userVol.getOwner());
 
-                    final String action = sEnvironmentToBroadcast.get(state);
+                    final String action = VolumeInfo.getBroadcastForEnvironment(envState);
                     if (action != null) {
                         final Intent intent = new Intent(action,
                                 Uri.fromFile(userVol.getPathFile()));
@@ -769,10 +587,14 @@
         // Record user as started so newly mounted volumes kick off events
         // correctly, then synthesize events for any already-mounted volumes.
         synchronized (mVolumes) {
-            for (Volume vol : mVolumes.values()) {
-                if (vol.isVisibleToUser(userId) && vol.state == Volume.STATE_MOUNTED) {
-                    final StorageVolume userVol = vol.buildVolumeForUser(userId);
+            for (int i = 0; i < mVolumes.size(); i++) {
+                final VolumeInfo vol = mVolumes.valueAt(i);
+                if (vol.isVisibleToUser(userId) && vol.state == VolumeInfo.STATE_MOUNTED) {
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
                     mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
+
+                    mCallbacks.notifyStorageStateChanged(userVol.getPath(),
+                            Environment.MEDIA_MOUNTED, Environment.MEDIA_MOUNTED);
                 }
             }
             mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userId);
@@ -792,23 +614,6 @@
         }
     }
 
-    private final class MountServiceBinderListener implements IBinder.DeathRecipient {
-        final IMountServiceListener mListener;
-
-        MountServiceBinderListener(IMountServiceListener listener) {
-            mListener = listener;
-        }
-
-        @Override
-        public void binderDied() {
-            if (LOCAL_LOGD) Slog.d(TAG, "An IMountServiceListener has died!");
-            synchronized (mListeners) {
-                mListeners.remove(this);
-                mListener.asBinder().unlinkToDeath(this, 0);
-            }
-        }
-    }
-
     void runIdleMaintenance(Runnable callback) {
         mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback));
     }
@@ -906,12 +711,12 @@
                 if (cooked.length != 3) break;
                 final String id = cooked[1];
                 final int flags = Integer.parseInt(cooked[2]);
-                mDisks.put(id, new Disk(id, flags));
+                mDisks.put(id, new DiskInfo(id, flags));
                 break;
             }
             case VoldResponseCode.DISK_SIZE_CHANGED: {
                 if (cooked.length != 3) break;
-                final Disk disk = mDisks.get(cooked[1]);
+                final DiskInfo disk = mDisks.get(cooked[1]);
                 if (disk != null) {
                     disk.size = Long.parseLong(cooked[2]);
                 }
@@ -919,7 +724,7 @@
             }
             case VoldResponseCode.DISK_LABEL_CHANGED: {
                 if (cooked.length != 3) break;
-                final Disk disk = mDisks.get(cooked[1]);
+                final DiskInfo disk = mDisks.get(cooked[1]);
                 if (disk != null) {
                     disk.label = cooked[2];
                 }
@@ -927,10 +732,10 @@
             }
             case VoldResponseCode.DISK_VOLUME_CREATED: {
                 if (cooked.length != 3) break;
-                final Disk disk = mDisks.get(cooked[1]);
-                final Volume vol = mVolumes.get(cooked[2]);
-                if (disk != null && vol != null) {
-                    disk.volumes.add(vol);
+                final DiskInfo disk = mDisks.get(cooked[1]);
+                final String volId = cooked[2];
+                if (disk != null) {
+                    disk.volumes = ArrayUtils.appendElement(String.class, disk.volumes, volId);
                 }
                 break;
             }
@@ -944,14 +749,15 @@
                 if (cooked.length != 3) break;
                 final String id = cooked[1];
                 final int type = Integer.parseInt(cooked[2]);
-                final Volume vol = new Volume(id, type);
+                final int mtpIndex = allocateMtpIndex(id);
+                final VolumeInfo vol = new VolumeInfo(id, type, mtpIndex);
                 mVolumes.put(id, vol);
                 onVolumeCreatedLocked(vol);
                 break;
             }
             case VoldResponseCode.VOLUME_STATE_CHANGED: {
                 if (cooked.length != 3) break;
-                final Volume vol = mVolumes.get(cooked[1]);
+                final VolumeInfo vol = mVolumes.get(cooked[1]);
                 if (vol != null) {
                     final int oldState = vol.state;
                     final int newState = Integer.parseInt(cooked[2]);
@@ -962,7 +768,7 @@
             }
             case VoldResponseCode.VOLUME_FS_TYPE_CHANGED: {
                 if (cooked.length != 3) break;
-                final Volume vol = mVolumes.get(cooked[1]);
+                final VolumeInfo vol = mVolumes.get(cooked[1]);
                 if (vol != null) {
                     vol.fsType = cooked[2];
                 }
@@ -970,7 +776,7 @@
             }
             case VoldResponseCode.VOLUME_FS_UUID_CHANGED: {
                 if (cooked.length != 3) break;
-                final Volume vol = mVolumes.get(cooked[1]);
+                final VolumeInfo vol = mVolumes.get(cooked[1]);
                 if (vol != null) {
                     vol.fsUuid = cooked[2];
                 }
@@ -978,7 +784,7 @@
             }
             case VoldResponseCode.VOLUME_FS_LABEL_CHANGED: {
                 if (cooked.length != 3) break;
-                final Volume vol = mVolumes.get(cooked[1]);
+                final VolumeInfo vol = mVolumes.get(cooked[1]);
                 if (vol != null) {
                     vol.fsLabel = cooked[2];
                 }
@@ -986,13 +792,14 @@
             }
             case VoldResponseCode.VOLUME_PATH_CHANGED: {
                 if (cooked.length != 3) break;
-                final Volume vol = mVolumes.get(cooked[1]);
+                final VolumeInfo vol = mVolumes.get(cooked[1]);
                 if (vol != null) {
                     vol.path = cooked[2];
                 }
                 break;
             }
             case VoldResponseCode.VOLUME_DESTROYED: {
+                // TODO: send ACTION_MEDIA_REMOVED broadcast
                 if (cooked.length != 2) break;
                 mVolumes.remove(cooked[1]);
                 break;
@@ -1010,73 +817,61 @@
         return true;
     }
 
-    private void onVolumeCreatedLocked(Volume vol) {
-        final boolean primaryPhysical = SystemProperties.getBoolean(PROP_PRIMARY_PHYSICAL, false);
-        if (vol.type == Volume.TYPE_EMULATED && !primaryPhysical) {
-            vol.flags |= Volume.FLAG_PRIMARY;
-            vol.flags |= Volume.FLAG_VISIBLE;
+    private void onVolumeCreatedLocked(VolumeInfo vol) {
+        final boolean primaryPhysical = SystemProperties.getBoolean(
+                StorageManager.PROP_PRIMARY_PHYSICAL, false);
+        if (vol.type == VolumeInfo.TYPE_EMULATED && !primaryPhysical) {
+            vol.flags |= VolumeInfo.FLAG_PRIMARY;
+            vol.flags |= VolumeInfo.FLAG_VISIBLE;
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
 
-        } else if (vol.type == Volume.TYPE_PUBLIC) {
+        } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
             if (primaryPhysical) {
-                vol.flags |= Volume.FLAG_PRIMARY;
+                vol.flags |= VolumeInfo.FLAG_PRIMARY;
             }
-            vol.flags |= Volume.FLAG_VISIBLE;
+            vol.flags |= VolumeInfo.FLAG_VISIBLE;
             vol.userId = UserHandle.USER_OWNER;
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
 
+        } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+            mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
+
         } else {
             Slog.d(TAG, "Skipping automatic mounting of " + vol);
         }
     }
 
-    private void onVolumeStateChangedLocked(Volume vol, int oldState, int newState) {
-        // Kick state changed event towards all started users. Any users
-        // started after this point will trigger additional
-        // user-specific broadcasts.
-        for (int userId : mStartedUsers) {
-            if (vol.isVisibleToUser(userId)) {
-                final StorageVolume userVol = vol.buildVolumeForUser(userId);
-                mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
-            }
-        }
+    private void onVolumeStateChangedLocked(VolumeInfo vol, int oldState, int newState) {
+        mCallbacks.notifyVolumeStateChanged(vol.clone(), oldState, newState);
 
-        // Tell PackageManager about changes to primary volume state, but only
-        // when not emulated.
-        if (vol.isPrimary() && vol.type == Volume.TYPE_PUBLIC) {
-            if (vol.state == Volume.STATE_MOUNTED) {
-                mPms.updateExternalMediaStatus(true, false);
+        final String oldStateEnv = VolumeInfo.getEnvironmentForState(oldState);
+        final String newStateEnv = VolumeInfo.getEnvironmentForState(newState);
 
-            } else if (vol.state == Volume.STATE_UNMOUNTING) {
-                mPms.updateExternalMediaStatus(false, false);
+        if (!Objects.equals(oldStateEnv, newStateEnv)) {
+            // Kick state changed event towards all started users. Any users
+            // started after this point will trigger additional
+            // user-specific broadcasts.
+            for (int userId : mStartedUsers) {
+                if (vol.isVisibleToUser(userId)) {
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
+                    mHandler.obtainMessage(H_VOLUME_BROADCAST, userVol).sendToTarget();
 
-                // TODO: this should eventually be handled by new ObbVolume state changes
-                /*
-                 * Some OBBs might have been unmounted when this volume was
-                 * unmounted, so send a message to the handler to let it know to
-                 * remove those from the list of mounted OBBS.
-                 */
-                mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
-                        OBB_FLUSH_MOUNT_STATE, vol.path));
-            }
-        }
-
-        final String oldEnvState = sStateToEnvironment.get(oldState);
-        final String newEnvState = sStateToEnvironment.get(newState);
-
-        synchronized (mListeners) {
-            for (int i = mListeners.size() -1; i >= 0; i--) {
-                MountServiceBinderListener bl = mListeners.get(i);
-                try {
-                    bl.mListener.onStorageStateChanged(vol.path, oldEnvState, newEnvState);
-                } catch (RemoteException rex) {
-                    Slog.e(TAG, "Listener dead");
-                    mListeners.remove(i);
-                } catch (Exception ex) {
-                    Slog.e(TAG, "Listener failed", ex);
+                    mCallbacks.notifyStorageStateChanged(userVol.getPath(), oldStateEnv,
+                            newStateEnv);
                 }
             }
         }
+
+        if (vol.type == VolumeInfo.TYPE_PUBLIC && vol.state == VolumeInfo.STATE_UNMOUNTING) {
+            // TODO: this should eventually be handled by new ObbVolume state changes
+            /*
+             * Some OBBs might have been unmounted when this volume was
+             * unmounted, so send a message to the handler to let it know to
+             * remove those from the list of mounted OBBS.
+             */
+            mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(
+                    OBB_FLUSH_MOUNT_STATE, vol.path));
+        }
     }
 
     private void enforcePermission(String perm) {
@@ -1099,6 +894,7 @@
         sSelf = this;
 
         mContext = context;
+        mCallbacks = new Callbacks(FgThread.get().getLooper());
 
         // XXX: This will go away soon in favor of IMountServiceObserver
         mPms = (PackageManagerService) ServiceManager.getService("package");
@@ -1153,28 +949,14 @@
      * Exposed API calls below here
      */
 
+    @Override
     public void registerListener(IMountServiceListener listener) {
-        synchronized (mListeners) {
-            MountServiceBinderListener bl = new MountServiceBinderListener(listener);
-            try {
-                listener.asBinder().linkToDeath(bl, 0);
-                mListeners.add(bl);
-            } catch (RemoteException rex) {
-                Slog.e(TAG, "Failed to link to listener death");
-            }
-        }
+        mCallbacks.register(listener);
     }
 
+    @Override
     public void unregisterListener(IMountServiceListener listener) {
-        synchronized (mListeners) {
-            for(MountServiceBinderListener bl : mListeners) {
-                if (bl.mListener.asBinder() == listener.asBinder()) {
-                    mListeners.remove(mListeners.indexOf(bl));
-                    listener.asBinder().unlinkToDeath(bl, 0);
-                    return;
-                }
-            }
-        }
+        mCallbacks.unregister(listener);
     }
 
     @Override
@@ -1186,104 +968,134 @@
     }
 
     @Override
-    @Deprecated
     public boolean isUsbMassStorageConnected() {
-        return false;
+        throw new UnsupportedOperationException();
     }
 
     @Override
-    @Deprecated
     public void setUsbMassStorageEnabled(boolean enable) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    @Deprecated
     public boolean isUsbMassStorageEnabled() {
-        return false;
+        throw new UnsupportedOperationException();
     }
 
-    /**
-     * @return state of the volume at the specified mount point
-     */
     @Override
-    @Deprecated
     public String getVolumeState(String mountPoint) {
-        // TODO: pretend that we're unmounted when encrypting?
-        // SystemProperties.get("vold.encrypt_progress")
-
-        final Volume vol = findVolumeByLegacyPath(mountPoint);
-        return sStateToEnvironment.get(vol.state);
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public boolean isExternalStorageEmulated() {
-        return Environment.isExternalStorageEmulated();
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public int mountVolume(String path) {
-        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-        waitForReady();
-
-        final Volume vol = findVolumeByLegacyPath(path);
-        if (vol != null) {
-            if (vol.type == Volume.TYPE_PUBLIC || vol.type == Volume.TYPE_PRIVATE) {
-                enforceUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
-            }
-            try {
-                vol.mount();
-                return 0;
-            } catch (NativeDaemonConnectorException ignored) {
-            }
-        } else {
-            Slog.w(TAG, "Unknown volume for path " + path);
-        }
-        return -1;
+        mount(findVolumeIdForPath(path));
+        return 0;
     }
 
     @Override
     public void unmountVolume(String path, boolean force, boolean removeEncryption) {
-        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
-        waitForReady();
-
-        final Volume vol = findVolumeByLegacyPath(path);
-        if (vol != null) {
-            // TODO: expand PMS to know about multiple volumes
-            if (vol.isPrimary()) {
-                synchronized (mUnmountLock) {
-                    mUnmountSignal = new CountDownLatch(1);
-                    mPms.updateExternalMediaStatus(false, true);
-                    waitForLatch(mUnmountSignal, "mUnmountSignal");
-                    mUnmountSignal = null;
-                }
-            }
-
-            try {
-                vol.unmount();
-            } catch (NativeDaemonConnectorException ignored) {
-            }
-        } else {
-            Slog.w(TAG, "Unknown volume for path " + path);
-        }
+        unmount(findVolumeIdForPath(path));
     }
 
     @Override
     public int formatVolume(String path) {
+        format(findVolumeIdForPath(path));
+        return 0;
+    }
+
+    @Override
+    public void mount(String volId) {
+        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+        waitForReady();
+
+        final VolumeInfo vol = findVolumeById(volId);
+        if (vol.type == VolumeInfo.TYPE_PUBLIC || vol.type == VolumeInfo.TYPE_PRIVATE) {
+            enforceUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA);
+        }
+        try {
+            mConnector.execute("volume", "mount", vol.id, vol.flags, vol.userId);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void unmount(String volId) {
+        enforcePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS);
+        waitForReady();
+
+        final VolumeInfo vol = findVolumeById(volId);
+
+        // TODO: expand PMS to know about multiple volumes
+        if (vol.isPrimary()) {
+            synchronized (mUnmountLock) {
+                mUnmountSignal = new CountDownLatch(1);
+                mPms.updateExternalMediaStatus(false, true);
+                waitForLatch(mUnmountSignal, "mUnmountSignal");
+                mUnmountSignal = null;
+            }
+        }
+
+        try {
+            mConnector.execute("volume", "unmount", vol.id);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void format(String volId) {
         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
         waitForReady();
 
-        final Volume vol = findVolumeByLegacyPath(path);
-        if (vol != null) {
-            try {
-                vol.format();
-                return 0;
-            } catch (NativeDaemonConnectorException ignored) {
-            }
-        } else {
-            Slog.w(TAG, "Unknown volume for path " + path);
+        final VolumeInfo vol = findVolumeById(volId);
+        try {
+            mConnector.execute("volume", "format", vol.id);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
         }
-        return -1;
+    }
+
+    @Override
+    public void partitionPublic(String diskId) {
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+        waitForReady();
+
+        try {
+            mConnector.execute("volume", "partition", diskId, "public");
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void partitionPrivate(String diskId) {
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+        waitForReady();
+
+        try {
+            mConnector.execute("volume", "partition", diskId, "private");
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
+    public void partitionMixed(String diskId, int ratio) {
+        enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
+        waitForReady();
+
+        try {
+            mConnector.execute("volume", "partition", diskId, "mixed", ratio);
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
     }
 
     @Override
@@ -1315,8 +1127,9 @@
 
     private void warnOnNotMounted() {
         synchronized (mLock) {
-            for (Volume vol : mVolumes.values()) {
-                if (vol.isPrimary() && vol.state == Volume.STATE_MOUNTED) {
+            for (int i = 0; i < mVolumes.size(); i++) {
+                final VolumeInfo vol = mVolumes.valueAt(i);
+                if (vol.isPrimary() && vol.state == VolumeInfo.STATE_MOUNTED) {
                     // Cool beans, we have a mounted primary volume
                     return;
                 }
@@ -2012,17 +1825,14 @@
 
     @Override
     public StorageVolume[] getVolumeList(int userId) {
-        if (UserHandle.getCallingUserId() != userId) {
-            mContext.enforceCallingOrSelfPermission(
-                    android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE, "getVolumeList");
-        }
-
-        final ArrayList<StorageVolume> res = Lists.newArrayList();
+        final ArrayList<StorageVolume> res = new ArrayList<>();
         boolean foundPrimary = false;
+
         synchronized (mLock) {
-            for (Volume vol : mVolumes.values()) {
+            for (int i = 0; i < mVolumes.size(); i++) {
+                final VolumeInfo vol = mVolumes.valueAt(i);
                 if (vol.isVisibleToUser(userId)) {
-                    final StorageVolume userVol = vol.buildVolumeForUser(userId);
+                    final StorageVolume userVol = vol.buildStorageVolume(mContext, userId);
                     if (vol.isPrimary()) {
                         res.add(0, userVol);
                         foundPrimary = true;
@@ -2034,14 +1844,14 @@
         }
 
         if (!foundPrimary) {
-            Slog.w(TAG, "No primary storage defined yet; hacking together a stub");
+            Log.w(TAG, "No primary storage defined yet; hacking together a stub");
 
             final boolean primaryPhysical = SystemProperties.getBoolean(
-                    PROP_PRIMARY_PHYSICAL, false);
+                    StorageManager.PROP_PRIMARY_PHYSICAL, false);
 
             final String id = "stub_primary";
             final File path = Environment.getLegacyExternalStorageDirectory();
-            final int descriptionId = android.R.string.unknownName;
+            final String description = mContext.getString(android.R.string.unknownName);
             final boolean primary = true;
             final boolean removable = primaryPhysical;
             final boolean emulated = !primaryPhysical;
@@ -2050,17 +1860,38 @@
             final long maxFileSize = 0L;
             final UserHandle owner = new UserHandle(userId);
             final String uuid = null;
-            final String userLabel = null;
             final String state = Environment.MEDIA_REMOVED;
 
             res.add(0, new StorageVolume(id, MtpStorage.getStorageIdForIndex(0), path,
-                    descriptionId, primary, removable, emulated, mtpReserveSize,
-                    allowMassStorage, maxFileSize, owner, uuid, userLabel, state));
+                    description, primary, removable, emulated, mtpReserveSize,
+                    allowMassStorage, maxFileSize, owner, uuid, state));
         }
 
         return res.toArray(new StorageVolume[res.size()]);
     }
 
+    @Override
+    public DiskInfo[] getDisks() {
+        synchronized (mLock) {
+            final DiskInfo[] res = new DiskInfo[mDisks.size()];
+            for (int i = 0; i < mDisks.size(); i++) {
+                res[i] = mDisks.valueAt(i);
+            }
+            return res;
+        }
+    }
+
+    @Override
+    public VolumeInfo[] getVolumes() {
+        synchronized (mLock) {
+            final VolumeInfo[] res = new VolumeInfo[mVolumes.size()];
+            for (int i = 0; i < mVolumes.size(); i++) {
+                res[i] = mVolumes.valueAt(i);
+            }
+            return res;
+        }
+    }
+
     private void addObbStateLocked(ObbState obbState) throws RemoteException {
         final IBinder binder = obbState.getBinder();
         List<ObbState> obbStates = mObbMounts.get(binder);
@@ -2561,6 +2392,72 @@
         return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath();
     }
 
+    private static class Callbacks extends Handler {
+        private static final int MSG_STORAGE_STATE_CHANGED = 1;
+        private static final int MSG_VOLUME_STATE_CHANGED = 2;
+
+        private final RemoteCallbackList<IMountServiceListener>
+                mCallbacks = new RemoteCallbackList<>();
+
+        public Callbacks(Looper looper) {
+            super(looper);
+        }
+
+        public void register(IMountServiceListener callback) {
+            mCallbacks.register(callback);
+        }
+
+        public void unregister(IMountServiceListener callback) {
+            mCallbacks.unregister(callback);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final SomeArgs args = (SomeArgs) msg.obj;
+            final int n = mCallbacks.beginBroadcast();
+            for (int i = 0; i < n; i++) {
+                final IMountServiceListener callback = mCallbacks.getBroadcastItem(i);
+                try {
+                    invokeCallback(callback, msg.what, args);
+                } catch (RemoteException ignored) {
+                }
+            }
+            mCallbacks.finishBroadcast();
+            args.recycle();
+        }
+
+        private void invokeCallback(IMountServiceListener callback, int what, SomeArgs args)
+                throws RemoteException {
+            switch (what) {
+                case MSG_STORAGE_STATE_CHANGED: {
+                    callback.onStorageStateChanged((String) args.arg1, (String) args.arg2,
+                            (String) args.arg3);
+                    break;
+                }
+                case MSG_VOLUME_STATE_CHANGED: {
+                    callback.onVolumeStateChanged((VolumeInfo) args.arg1, args.argi2, args.argi3);
+                    break;
+                }
+            }
+        }
+
+        private void notifyStorageStateChanged(String path, String oldState, String newState) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = path;
+            args.arg2 = oldState;
+            args.arg3 = newState;
+            obtainMessage(MSG_STORAGE_STATE_CHANGED, args).sendToTarget();
+        }
+
+        private void notifyVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+            final SomeArgs args = SomeArgs.obtain();
+            args.arg1 = vol;
+            args.argi2 = oldState;
+            args.argi3 = newState;
+            obtainMessage(MSG_VOLUME_STATE_CHANGED, args).sendToTarget();
+        }
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
@@ -2601,7 +2498,8 @@
             pw.println();
             pw.println("Disks:");
             pw.increaseIndent();
-            for (Disk disk : mDisks.values()) {
+            for (int i = 0; i < mDisks.size(); i++) {
+                final DiskInfo disk = mDisks.valueAt(i);
                 disk.dump(pw);
             }
             pw.decreaseIndent();
@@ -2609,7 +2507,8 @@
             pw.println();
             pw.println("Volumes:");
             pw.increaseIndent();
-            for (Volume vol : mVolumes.values()) {
+            for (int i = 0; i < mVolumes.size(); i++) {
+                final VolumeInfo vol = mVolumes.valueAt(i);
                 vol.dump(pw);
             }
             pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 7b542be..b5b62b4 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -210,6 +210,7 @@
 
     private boolean mMobileActivityFromRadio = false;
     private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
+    private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW;
 
     private final RemoteCallbackList<INetworkActivityListener> mNetworkActivityListeners =
             new RemoteCallbackList<INetworkActivityListener>();
@@ -434,6 +435,16 @@
             }
         }
 
+        if (ConnectivityManager.isNetworkTypeWifi(type)) {
+            if (mLastPowerStateFromWifi != powerState) {
+                mLastPowerStateFromWifi = powerState;
+                try {
+                    getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
         boolean isActive = powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
                 || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
 
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index b36f515..56f9942 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -18,14 +18,18 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
+import android.app.PendingIntent;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.service.persistentdata.IPersistentDataBlockService;
+import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Slog;
 
 import com.android.internal.R;
@@ -428,6 +432,29 @@
         }
 
         @Override
+        public void wipeIfAllowed(Bundle bundle, PendingIntent pi) {
+            // Should only be called by owner
+            if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
+                throw new SecurityException("Only the Owner is allowed to wipe");
+            }
+            // Caller must be able to query the the state of the PersistentDataBlock
+            enforcePersistentDataBlockAccess();
+            String allowedPackage = mContext.getResources()
+                    .getString(R.string.config_persistentDataPackageName);
+            Intent intent = new Intent();
+            intent.setPackage(allowedPackage);
+            intent.setAction(PersistentDataBlockManager.ACTION_WIPE_IF_ALLOWED);
+            intent.putExtras(bundle);
+            intent.putExtra(PersistentDataBlockManager.EXTRA_WIPE_IF_ALLOWED_CALLBACK, pi);
+            long id = Binder.clearCallingIdentity();
+            try {
+                mContext.sendBroadcastAsUser(intent, UserHandle.OWNER);
+            } finally {
+                restoreCallingIdentity(id);
+            }
+        }
+
+        @Override
         public void setOemUnlockEnabled(boolean enabled) {
             // do not allow monkey to flip the flag
             if (ActivityManager.isUserAMonkey()) {
@@ -450,10 +477,7 @@
 
         @Override
         public int getDataBlockSize() {
-            if (mContext.checkCallingPermission(Manifest.permission.ACCESS_PDB_STATE)
-                    != PackageManager.PERMISSION_GRANTED) {
-                enforceUid(Binder.getCallingUid());
-            }
+            enforcePersistentDataBlockAccess();
 
             DataInputStream inputStream;
             try {
@@ -475,6 +499,13 @@
             }
         }
 
+        private void enforcePersistentDataBlockAccess() {
+            if (mContext.checkCallingPermission(Manifest.permission.ACCESS_PDB_STATE)
+                    != PackageManager.PERMISSION_GRANTED) {
+                enforceUid(Binder.getCallingUid());
+            }
+        }
+
         @Override
         public long getMaximumDataBlockSize() {
             long actualSize = getBlockDeviceSize() - HEADER_SIZE - 1;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 3859904..3dece49 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1519,6 +1519,7 @@
         } catch (DeadObjectException e) {
             Slog.w(TAG, "Application dead when creating service " + r);
             mAm.appDiedLocked(app);
+            throw e;
         } finally {
             if (!created) {
                 // Keep the executeNesting count accurate.
@@ -2193,8 +2194,16 @@
             }
         }
 
-        // First clear app state from services.
-        for (int i=app.services.size()-1; i>=0; i--) {
+        // Clean up any connections this application has to other services.
+        for (int i = app.connections.size() - 1; i >= 0; i--) {
+            ConnectionRecord r = app.connections.valueAt(i);
+            removeConnectionLocked(r, app, null);
+        }
+        updateServiceConnectionActivitiesLocked(app);
+        app.connections.clear();
+
+        // Clear app state from services.
+        for (int i = app.services.size() - 1; i >= 0; i--) {
             ServiceRecord sr = app.services.valueAt(i);
             synchronized (sr.stats.getBatteryStats()) {
                 sr.stats.stopLaunchedLocked();
@@ -2254,14 +2263,6 @@
             }
         }
 
-        // Clean up any connections this application has to other services.
-        for (int i=app.connections.size()-1; i>=0; i--) {
-            ConnectionRecord r = app.connections.valueAt(i);
-            removeConnectionLocked(r, app, null);
-        }
-        updateServiceConnectionActivitiesLocked(app);
-        app.connections.clear();
-
         ServiceMap smap = getServiceMap(app.userId);
 
         // Now do remaining service cleanup.
@@ -2294,7 +2295,7 @@
                 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
                         sr.userId, sr.crashCount, sr.shortName, app.pid);
                 bringDownServiceLocked(sr);
-            } else if (!allowRestart) {
+            } else if (!allowRestart || !mAm.isUserRunningLocked(sr.userId, false)) {
                 bringDownServiceLocked(sr);
             } else {
                 boolean canceled = scheduleServiceRestartLocked(sr, true);
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index fd4974e..d64e39f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -72,7 +72,8 @@
     static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
     static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
     static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
-    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
+    static final boolean DEBUG_VISIBILITY = DEBUG_ALL || false;
+    static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
 
     static final String POSTFIX_BACKUP = (APPEND_CATEGORY_NAME) ? "_Backup" : "";
     static final String POSTFIX_BROADCAST = (APPEND_CATEGORY_NAME) ? "_Broadcast" : "";
@@ -80,11 +81,29 @@
     static final String POSTFIX_CONFIGURATION = (APPEND_CATEGORY_NAME) ? "_Configuration" : "";
     static final String POSTFIX_FOCUS = (APPEND_CATEGORY_NAME) ? "_Focus" : "";
     static final String POSTFIX_IMMERSIVE = (APPEND_CATEGORY_NAME) ? "_Immersive" : "";
+    static final String POSTFIX_LOCKSCREEN = (APPEND_CATEGORY_NAME) ? "_LOCKSCREEN" : "";
     static final String POSTFIX_LRU = (APPEND_CATEGORY_NAME) ? "_LRU" : "";
     static final String POSTFIX_MU = "_MU";
     static final String POSTFIX_OOM_ADJ = (APPEND_CATEGORY_NAME) ? "_OomAdj" : "";
+    static final String POSTFIX_PAUSE = (APPEND_CATEGORY_NAME) ? "_Pause" : "";
+    static final String POSTFIX_POWER = (APPEND_CATEGORY_NAME) ? "_Power" : "";
+    static final String POSTFIX_PROCESS_OBSERVERS = (APPEND_CATEGORY_NAME)
+            ? "_ProcessObservers" : "";
+    static final String POSTFIX_PROCESSES = (APPEND_CATEGORY_NAME) ? "_Processes" : "";
+    static final String POSTFIX_PROVIDER = (APPEND_CATEGORY_NAME) ? "_Provider" : "";
+    static final String POSTFIX_PSS = (APPEND_CATEGORY_NAME) ? "_Pss" : "";
+    static final String POSTFIX_RESULTS = (APPEND_CATEGORY_NAME) ? "_Results" : "";
+    static final String POSTFIX_RECENTS = (APPEND_CATEGORY_NAME) ? "_Recents" : "";
     static final String POSTFIX_SERVICE = (APPEND_CATEGORY_NAME) ? "_Service" : "";
     static final String POSTFIX_SERVICE_EXECUTING =
             (APPEND_CATEGORY_NAME) ? "_ServiceExecuting" : "";
+    static final String POSTFIX_STACK = (APPEND_CATEGORY_NAME) ? "_Stack" : "";
+    static final String POSTFIX_SWITCH = (APPEND_CATEGORY_NAME) ? "_Switch" : "";
+    static final String POSTFIX_TASKS = (APPEND_CATEGORY_NAME) ? "_Tasks" : "";
+    static final String POSTFIX_THUMBNAILS = (APPEND_CATEGORY_NAME) ? "_Thumbnails" : "";
+    static final String POSTFIX_TRANSITION = (APPEND_CATEGORY_NAME) ? "_Transition" : "";
+    static final String POSTFIX_URI_PERMISSION = (APPEND_CATEGORY_NAME) ? "_UriPermission" : "";
+    static final String POSTFIX_USER_LEAVING = (APPEND_CATEGORY_NAME) ? "_UserLeaving" : "";
+    static final String POSTFIX_VISIBILITY = (APPEND_CATEGORY_NAME) ? "_Visibility" : "";
 
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c318370..0581e22 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26,12 +26,12 @@
 import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
-import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
-import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
-import static org.xmlpull.v1.XmlPullParser.START_TAG;
 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
+import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
 import android.Manifest;
 import android.app.AppOpsManager;
@@ -41,8 +41,8 @@
 import android.app.IAppTask;
 import android.app.ITaskStackListener;
 import android.app.ProfilerInfo;
-import android.app.admin.DevicePolicyManager;
 import android.app.usage.UsageEvents;
+import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.content.res.Resources;
@@ -61,8 +61,8 @@
 import android.util.ArraySet;
 import android.util.DebugUtils;
 import android.util.SparseIntArray;
-
 import android.view.Display;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.DumpHeapActivity;
@@ -96,11 +96,11 @@
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.wm.AppTransition;
 import com.android.server.wm.WindowManagerService;
-
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
 import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -259,37 +259,30 @@
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
     private static final String TAG_IMMERSIVE = TAG + POSTFIX_IMMERSIVE;
+    private static final String TAG_LOCKSCREEN = TAG + POSTFIX_LOCKSCREEN;
     private static final String TAG_LRU = TAG + POSTFIX_LRU;
     private static final String TAG_MU = TAG + POSTFIX_MU;
     private static final String TAG_OOM_ADJ = TAG + POSTFIX_OOM_ADJ;
+    private static final String TAG_POWER = TAG + POSTFIX_POWER;
+    private static final String TAG_PROCESS_OBSERVERS = TAG + POSTFIX_PROCESS_OBSERVERS;
+    private static final String TAG_PROCESSES = TAG + POSTFIX_PROCESSES;
+    private static final String TAG_PROVIDER = TAG + POSTFIX_PROVIDER;
+    private static final String TAG_PSS = TAG + POSTFIX_PSS;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_SERVICE = TAG + POSTFIX_SERVICE;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_URI_PERMISSION = TAG + POSTFIX_URI_PERMISSION;
+    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
-    // TODO(ogunwale): Migrate all the constants below to use ActivityManagerDebugConfig class.
-    static final boolean DEBUG_PAUSE = DEBUG_ALL || false;
-    static final boolean DEBUG_POWER = DEBUG_ALL || false;
-    static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false;
-    static final boolean DEBUG_PROCESS_OBSERVERS = DEBUG_ALL || false;
-    static final boolean DEBUG_PROCESSES = DEBUG_ALL || false;
-    static final boolean DEBUG_PROVIDER = DEBUG_ALL || false;
-    static final boolean DEBUG_RESULTS = DEBUG_ALL || false;
-    static final boolean DEBUG_SERVICE = DEBUG_ALL || false;
-    static final boolean DEBUG_SERVICE_EXECUTING = DEBUG_ALL || false;
-    static final boolean DEBUG_STACK = DEBUG_ALL || false;
-    static final boolean DEBUG_SWITCH = DEBUG_ALL || false;
-    static final boolean DEBUG_TASKS = DEBUG_ALL || false;
-    static final boolean DEBUG_THUMBNAILS = DEBUG_ALL || false;
-    static final boolean DEBUG_TRANSITION = DEBUG_ALL || false;
-    static final boolean DEBUG_URI_PERMISSION = DEBUG_ALL || false;
-    static final boolean DEBUG_USER_LEAVING = DEBUG_ALL || false;
-    static final boolean DEBUG_VISBILITY = DEBUG_ALL || false;
-    static final boolean DEBUG_PSS = DEBUG_ALL || false;
-    static final boolean DEBUG_LOCKSCREEN = DEBUG_ALL || false;
-    static final boolean DEBUG_RECENTS = DEBUG_ALL || false;
-
-    // Control over CPU and battery monitoring.
-    static final long BATTERY_STATS_TIME = 30*60*1000;      // write battery stats every 30 minutes.
+    /** Control over CPU and battery monitoring */
+    // write battery stats every 30 minutes.
+    static final long BATTERY_STATS_TIME = 30 * 60 * 1000;
     static final boolean MONITOR_CPU_USAGE = true;
-    static final long MONITOR_CPU_MIN_TIME = 5*1000;        // don't sample cpu less than every 5 seconds.
-    static final long MONITOR_CPU_MAX_TIME = 0x0fffffff;    // wait possibly forever for next cpu sample.
+    // don't sample cpu less than every 5 seconds.
+    static final long MONITOR_CPU_MIN_TIME = 5 * 1000;
+    // wait possibly forever for next cpu sample.
+    static final long MONITOR_CPU_MAX_TIME = 0x0fffffff;
     static final boolean MONITOR_THREAD_CPU_USAGE = false;
 
     // The flags that are set for all calls we make to the package manager.
@@ -436,6 +429,11 @@
      */
     ActivityInfo mLastAddedTaskActivity;
 
+    /**
+     * List of packages whitelisted by DevicePolicyManager for locktask. Indexed by userId.
+     */
+    SparseArray<String[]> mLockTaskPackages = new SparseArray<>();
+
     public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
         public final Bundle extras;
@@ -989,6 +987,12 @@
     private boolean mSleeping = false;
 
     /**
+     * The process state used for processes that are running the top activities.
+     * This changes between TOP and TOP_SLEEPING to following mSleeping.
+     */
+    int mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
+
+    /**
      * Set while we are running a voice interaction.  This overrides
      * sleeping while it is active.
      */
@@ -1131,7 +1135,7 @@
     boolean mAutoStopProfiler = false;
     int mProfileType = 0;
     String mOpenGlTraceApp = null;
-    final ArrayMap<String, Long> mMemWatchProcesses = new ArrayMap<>();
+    final ProcessMap<Pair<Long, String>> mMemWatchProcesses = new ProcessMap<>();
     String mMemWatchDumpProcName;
     String mMemWatchDumpFile;
     int mMemWatchDumpPid;
@@ -1837,18 +1841,28 @@
                 final String procName;
                 final int uid;
                 final long memLimit;
+                final String reportPackage;
                 synchronized (ActivityManagerService.this) {
                     procName = mMemWatchDumpProcName;
                     uid = mMemWatchDumpUid;
-                    Long limit = mMemWatchProcesses.get(procName);
-                    memLimit = limit != null ? limit : 0;
+                    Pair<Long, String> val = mMemWatchProcesses.get(procName, uid);
+                    if (val == null) {
+                        val = mMemWatchProcesses.get(procName, 0);
+                    }
+                    if (val != null) {
+                        memLimit = val.first;
+                        reportPackage = val.second;
+                    } else {
+                        memLimit = 0;
+                        reportPackage = null;
+                    }
                 }
                 if (procName == null) {
                     return;
                 }
 
-                if (DEBUG_PSS) Slog.d(TAG, "Showing dump heap notification from "
-                        + procName + "/" + uid);
+                if (DEBUG_PSS) Slog.d(TAG_PSS,
+                        "Showing dump heap notification from " + procName + "/" + uid);
 
                 INotificationManager inm = NotificationManager.getService();
                 if (inm == null) {
@@ -1874,6 +1888,9 @@
                 intent.setClassName("android", DumpHeapActivity.class.getName());
                 intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
                 intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+                if (reportPackage != null) {
+                    intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
+                }
                 int userId = UserHandle.getUserId(uid);
                 notification.setLatestEventInfo(mContext, text,
                         mContext.getText(R.string.dump_heap_notification_detail),
@@ -1946,7 +1963,7 @@
                     }
                     memInfo.readMemInfo();
                     synchronized (ActivityManagerService.this) {
-                        if (DEBUG_PSS) Slog.d(TAG, "Collected native and kernel memory in "
+                        if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in "
                                 + (SystemClock.uptimeMillis()-start) + "ms");
                         final long cachedKb = memInfo.getCachedSizeKb();
                         final long freeKb = memInfo.getFreeSizeKb();
@@ -1968,8 +1985,9 @@
                     long lastPssTime;
                     synchronized (ActivityManagerService.this) {
                         if (mPendingPssProcesses.size() <= 0) {
-                            if (mTestPssMode || DEBUG_PSS) Slog.d(TAG, "Collected PSS of " + num
-                                    + " processes in " + (SystemClock.uptimeMillis()-start) + "ms");
+                            if (mTestPssMode || DEBUG_PSS) Slog.d(TAG_PSS,
+                                    "Collected PSS of " + num + " processes in "
+                                    + (SystemClock.uptimeMillis() - start) + "ms");
                             mPendingPssProcesses.clear();
                             return;
                         }
@@ -2200,8 +2218,8 @@
         mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
 
         // User 0 is the first and only user that runs at boot.
-        mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
-        mUserLru.add(Integer.valueOf(0));
+        mStartedUsers.put(UserHandle.USER_OWNER, new UserStartedState(UserHandle.OWNER, true));
+        mUserLru.add(UserHandle.USER_OWNER);
         updateStartedUserArrayLocked();
 
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
@@ -2210,7 +2228,7 @@
         mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
 
         mConfiguration.setToDefaults();
-        mConfiguration.locale = Locale.getDefault();
+        mConfiguration.setLocale(Locale.getDefault());
 
         mConfigurationSeq = mConfiguration.seq = 1;
         mProcessCpuTracker.init();
@@ -2455,6 +2473,13 @@
         }
     }
 
+    @Override
+    public void batterySendBroadcast(Intent intent) {
+        broadcastIntentLocked(null, null, intent, null,
+                null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
+                Process.SYSTEM_UID, UserHandle.USER_ALL);
+    }
+
     /**
      * Initialize the application bind args. These are passed to each
      * process when the bindApplication() IPC is sent to the process. They're
@@ -2480,11 +2505,19 @@
     final void setFocusedActivityLocked(ActivityRecord r, String reason) {
         if (r != null && mFocusedActivity != r) {
             if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
+            ActivityRecord last = mFocusedActivity;
             mFocusedActivity = r;
             if (r.task != null && r.task.voiceInteractor != null) {
                 startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
             } else {
                 finishRunningVoiceLocked();
+                if (last != null && last.task.voiceSession != null) {
+                    // We had been in a voice interaction session, but now focused has
+                    // move to something different.  Just finish the session, we can't
+                    // return to it and retain the proper state and synchronization with
+                    // the voice interaction service.
+                    finishVoiceTask(last.task.voiceSession);
+                }
             }
             if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
                 mWindowManager.setFocusedApp(r.appToken, true);
@@ -2528,7 +2561,7 @@
 
     @Override
     public void notifyActivityDrawn(IBinder token) {
-        if (DEBUG_VISBILITY) Slog.d(TAG, "notifyActivityDrawn: token=" + token);
+        if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, "notifyActivityDrawn: token=" + token);
         synchronized (this) {
             ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
             if (r != null) {
@@ -2828,7 +2861,7 @@
         } else if (proc != null && !keepIfLarge
                 && mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
                 && proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
-            if (DEBUG_PSS) Slog.d(TAG, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
             if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
                 if (proc.baseProcessTracker != null) {
                     proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
@@ -2900,45 +2933,8 @@
         if (!isolated) {
             app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
             checkTime(startTime, "startProcess: after getProcessRecord");
-        } else {
-            // If this is an isolated process, it can't re-use an existing process.
-            app = null;
-        }
-        // We don't have to do anything more if:
-        // (1) There is an existing application record; and
-        // (2) The caller doesn't think it is dead, OR there is no thread
-        //     object attached to it so we know it couldn't have crashed; and
-        // (3) There is a pid assigned to it, so it is either starting or
-        //     already running.
-        if (DEBUG_PROCESSES) Slog.v(TAG, "startProcess: name=" + processName
-                + " app=" + app + " knownToBeDead=" + knownToBeDead
-                + " thread=" + (app != null ? app.thread : null)
-                + " pid=" + (app != null ? app.pid : -1));
-        if (app != null && app.pid > 0) {
-            if (!knownToBeDead || app.thread == null) {
-                // We already have the app running, or are waiting for it to
-                // come up (we have a pid but not yet its thread), so keep it.
-                if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
-                // If this is a new package in the process, add the package to the list
-                app.addPackage(info.packageName, info.versionCode, mProcessStats);
-                checkTime(startTime, "startProcess: done, added package to proc");
-                return app;
-            }
 
-            // An application record is attached to a previous process,
-            // clean it up now.
-            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app);
-            checkTime(startTime, "startProcess: bad proc running, killing");
-            Process.killProcessGroup(app.info.uid, app.pid);
-            handleAppDiedLocked(app, true, true);
-            checkTime(startTime, "startProcess: done killing old proc");
-        }
-
-        String hostingNameStr = hostingName != null
-                ? hostingName.flattenToShortString() : null;
-
-        if (!isolated) {
-            if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
+            if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
                 // If we are in the background, then check to see if this process
                 // is bad.  If so, we will just silently fail.
                 if (mBadProcesses.get(info.processName, info.uid) != null) {
@@ -2964,8 +2960,44 @@
                     }
                 }
             }
+        } else {
+            // If this is an isolated process, it can't re-use an existing process.
+            app = null;
         }
 
+        // We don't have to do anything more if:
+        // (1) There is an existing application record; and
+        // (2) The caller doesn't think it is dead, OR there is no thread
+        //     object attached to it so we know it couldn't have crashed; and
+        // (3) There is a pid assigned to it, so it is either starting or
+        //     already running.
+        if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "startProcess: name=" + processName
+                + " app=" + app + " knownToBeDead=" + knownToBeDead
+                + " thread=" + (app != null ? app.thread : null)
+                + " pid=" + (app != null ? app.pid : -1));
+        if (app != null && app.pid > 0) {
+            if (!knownToBeDead || app.thread == null) {
+                // We already have the app running, or are waiting for it to
+                // come up (we have a pid but not yet its thread), so keep it.
+                if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App already running: " + app);
+                // If this is a new package in the process, add the package to the list
+                app.addPackage(info.packageName, info.versionCode, mProcessStats);
+                checkTime(startTime, "startProcess: done, added package to proc");
+                return app;
+            }
+
+            // An application record is attached to a previous process,
+            // clean it up now.
+            if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_PROCESSES, "App died: " + app);
+            checkTime(startTime, "startProcess: bad proc running, killing");
+            Process.killProcessGroup(app.info.uid, app.pid);
+            handleAppDiedLocked(app, true, true);
+            checkTime(startTime, "startProcess: done killing old proc");
+        }
+
+        String hostingNameStr = hostingName != null
+                ? hostingName.flattenToShortString() : null;
+
         if (app == null) {
             checkTime(startTime, "startProcess: creating new process record");
             app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
@@ -2994,7 +3026,8 @@
             if (!mProcessesOnHold.contains(app)) {
                 mProcessesOnHold.add(app);
             }
-            if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
+            if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES,
+                    "System not ready, putting on hold: " + app);
             checkTime(startTime, "startProcess: returning with proc on hold");
             return app;
         }
@@ -3029,7 +3062,7 @@
             app.setPid(0);
         }
 
-        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
                 "startProcessLocked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
@@ -3198,7 +3231,8 @@
     }
 
     void updateUsageStats(ActivityRecord component, boolean resumed) {
-        if (DEBUG_SWITCH) Slog.d(TAG, "updateUsageStats: comp=" + component + "res=" + resumed);
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
+                "updateUsageStats: comp=" + component + "res=" + resumed);
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         if (resumed) {
             if (mUsageStatsService != null) {
@@ -3416,7 +3450,8 @@
             mPendingProcessChanges.toArray(mActiveProcessChanges);
             mAvailProcessChanges.addAll(mPendingProcessChanges);
             mPendingProcessChanges.clear();
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "*** Delivering " + N + " process changes");
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "*** Delivering " + N + " process changes");
         }
 
         int i = mProcessObservers.beginBroadcast();
@@ -3428,15 +3463,16 @@
                     for (int j=0; j<N; j++) {
                         ProcessChangeItem item = mActiveProcessChanges[j];
                         if ((item.changes&ProcessChangeItem.CHANGE_ACTIVITIES) != 0) {
-                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "ACTIVITIES CHANGED pid="
-                                    + item.pid + " uid=" + item.uid + ": "
-                                    + item.foregroundActivities);
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                                    "ACTIVITIES CHANGED pid=" + item.pid + " uid="
+                                    + item.uid + ": " + item.foregroundActivities);
                             observer.onForegroundActivitiesChanged(item.pid, item.uid,
                                     item.foregroundActivities);
                         }
                         if ((item.changes&ProcessChangeItem.CHANGE_PROCESS_STATE) != 0) {
-                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "PROCSTATE CHANGED pid="
-                                    + item.pid + " uid=" + item.uid + ": " + item.processState);
+                            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                                    "PROCSTATE CHANGED pid=" + item.pid + " uid=" + item.uid
+                                    + ": " + item.processState);
                             observer.onProcessStateChanged(item.pid, item.uid, item.processState);
                         }
                     }
@@ -4196,17 +4232,13 @@
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
 
-        if (!restarting) {
-            if (!mStackSupervisor.resumeTopActivitiesLocked()) {
-                // If there was nothing to resume, and we are not already
-                // restarting this process, but there is a visible activity that
-                // is hosted by the process...  then make sure all visible
-                // activities are running, taking care of restarting this
-                // process.
-                if (hasVisibleActivities) {
-                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
-                }
-            }
+        if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
+            // If there was nothing to resume, and we are not already
+            // restarting this process, but there is a visible activity that
+            // is hosted by the process...  then make sure all visible
+            // activities are running, taking care of restarting this
+            // process.
+            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
         }
     }
 
@@ -4352,7 +4384,7 @@
                     + ") has died and restarted (pid " + app.pid + ").");
             EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
         } else if (DEBUG_PROCESSES) {
-            Slog.d(TAG, "Received spurious death notification for thread "
+            Slog.d(TAG_PROCESSES, "Received spurious death notification for thread "
                     + thread.asBinder());
         }
     }
@@ -5387,9 +5419,8 @@
             boolean callerWillRestart, boolean allowRestart, String reason) {
         final String name = app.processName;
         final int uid = app.uid;
-        if (DEBUG_PROCESSES) Slog.d(
-            TAG, "Force removing proc " + app.toShortString() + " (" + name
-            + "/" + uid + ")");
+        if (DEBUG_PROCESSES) Slog.d(TAG_PROCESSES,
+            "Force removing proc " + app.toShortString() + " (" + name + "/" + uid + ")");
 
         mProcessNames.remove(name, uid);
         mIsolatedProcesses.remove(app.uid);
@@ -5633,7 +5664,7 @@
 
         // Remove this record from the list of starting applications.
         mPersistentStartingProcesses.remove(app);
-        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
+        if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
                 "Attach application locked removing on hold: " + app);
         mProcessesOnHold.remove(app);
 
@@ -5841,7 +5872,7 @@
                 ArrayList<ProcessRecord> procs =
                     new ArrayList<ProcessRecord>(mProcessesOnHold);
                 for (int ip=0; ip<NP; ip++) {
-                    if (DEBUG_PROCESSES) Slog.v(TAG, "Starting process on hold: "
+                    if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "Starting process on hold: "
                             + procs.get(ip));
                     startProcessLocked(procs.get(ip), "on-hold", null);
                 }
@@ -5982,7 +6013,7 @@
 
     @Override
     public final void activityDestroyed(IBinder token) {
-        if (DEBUG_SWITCH) Slog.v(TAG, "ACTIVITY DESTROYED: " + token);
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "ACTIVITY DESTROYED: " + token);
         synchronized (this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
@@ -6587,7 +6618,7 @@
      */
     private final boolean checkHoldingPermissionsLocked(
             IPackageManager pm, ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                 "checkHoldingPermissionsLocked: uri=" + grantUri + " uid=" + uid);
         if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
             if (ActivityManager.checkComponentPermission(INTERACT_ACROSS_USERS, uid, -1, true)
@@ -6635,8 +6666,8 @@
                     if (pp.match(path)) {
                         if (!readMet) {
                             final String pprperm = pp.getReadPermission();
-                            if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking read perm for "
-                                    + pprperm + " for " + pp.getPath()
+                            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                                    "Checking read perm for " + pprperm + " for " + pp.getPath()
                                     + ": match=" + pp.match(path)
                                     + " check=" + pm.checkUidPermission(pprperm, uid));
                             if (pprperm != null) {
@@ -6650,8 +6681,8 @@
                         }
                         if (!writeMet) {
                             final String ppwperm = pp.getWritePermission();
-                            if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Checking write perm "
-                                    + ppwperm + " for " + pp.getPath()
+                            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                                    "Checking write perm " + ppwperm + " for " + pp.getPath()
                                     + ": match=" + pp.match(path)
                                     + " check=" + pm.checkUidPermission(ppwperm, uid));
                             if (ppwperm != null) {
@@ -6796,7 +6827,7 @@
         }
 
         if (targetPkg != null) {
-            if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                     "Checking grant " + targetPkg + " permission to " + grantUri);
         }
 
@@ -6804,7 +6835,7 @@
 
         // If this is not a content: uri, we can't do anything with it.
         if (!ContentResolver.SCHEME_CONTENT.equals(grantUri.uri.getScheme())) {
-            if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                     "Can't grant URI permission for non-content URI: " + grantUri);
             return -1;
         }
@@ -6822,7 +6853,7 @@
             try {
                 targetUid = pm.getPackageUid(targetPkg, UserHandle.getUserId(callingUid));
                 if (targetUid < 0) {
-                    if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+                    if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                             "Can't grant URI permission no uid for: " + targetPkg);
                     return -1;
                 }
@@ -6835,7 +6866,7 @@
             // First...  does the target actually need this permission?
             if (checkHoldingPermissionsLocked(pm, pi, grantUri, targetUid, modeFlags)) {
                 // No need to grant the target this permission.
-                if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                         "Target " + targetPkg + " already has full permission to " + grantUri);
                 return -1;
             }
@@ -6932,7 +6963,7 @@
         // to the uri, and the target doesn't.  Let's now give this to
         // the target.
 
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                 "Granting " + targetPkg + "/" + targetUid + " permission to " + grantUri);
 
         final String authority = grantUri.uri.getAuthority();
@@ -6990,7 +7021,7 @@
      */
     NeededUriGrants checkGrantUriPermissionFromIntentLocked(int callingUid,
             String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                 "Checking URI perm to data=" + (intent != null ? intent.getData() : null)
                 + " clip=" + (intent != null ? intent.getClipData() : null)
                 + " from " + intent + "; flags=0x"
@@ -7024,10 +7055,9 @@
                 return null;
             }
             if (targetUid < 0) {
-                if (DEBUG_URI_PERMISSION) {
-                    Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg
-                            + " on user " + targetUserId);
-                }
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                        "Can't grant URI permission no uid for: " + targetPkg
+                        + " on user " + targetUserId);
                 return null;
             }
         }
@@ -7134,7 +7164,7 @@
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(
                     perm.targetUid);
             if (perms != null) {
-                if (DEBUG_URI_PERMISSION) Slog.v(TAG,
+                if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                         "Removing " + perm.targetUid + " permission to " + perm.uri);
 
                 perms.remove(perm.uri);
@@ -7146,7 +7176,8 @@
     }
 
     private void revokeUriPermissionLocked(int callingUid, GrantUri grantUri, final int modeFlags) {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                "Revoking all granted permissions to " + grantUri);
 
         final IPackageManager pm = AppGlobals.getPackageManager();
         final String authority = grantUri.uri.getAuthority();
@@ -7168,9 +7199,9 @@
                     final UriPermission perm = it.next();
                     if (perm.uri.sourceUserId == grantUri.sourceUserId
                             && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
-                        if (DEBUG_URI_PERMISSION)
-                            Slog.v(TAG, "Revoking non-owned " + perm.targetUid +
-                                    " permission to " + perm.uri);
+                        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                                "Revoking non-owned " + perm.targetUid
+                                + " permission to " + perm.uri);
                         persistChanged |= perm.revokeModes(
                                 modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, false);
                         if (perm.modeFlags == 0) {
@@ -7200,8 +7231,7 @@
                 final UriPermission perm = it.next();
                 if (perm.uri.sourceUserId == grantUri.sourceUserId
                         && perm.uri.uri.isPathPrefixMatch(grantUri.uri)) {
-                    if (DEBUG_URI_PERMISSION)
-                        Slog.v(TAG,
+                    if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
                                 "Revoking " + perm.targetUid + " permission to " + perm.uri);
                     persistChanged |= perm.revokeModes(
                             modeFlags | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, true);
@@ -7386,7 +7416,7 @@
     }
 
     private void writeGrantedUriPermissions() {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "writeGrantedUriPermissions()");
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "writeGrantedUriPermissions()");
 
         // Snapshot permissions so we can persist without lock
         ArrayList<UriPermission.Snapshot> persist = Lists.newArrayList();
@@ -7434,7 +7464,7 @@
     }
 
     private void readGrantedUriPermissionsLocked() {
-        if (DEBUG_URI_PERMISSION) Slog.v(TAG, "readGrantedUriPermissions()");
+        if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION, "readGrantedUriPermissions()");
 
         final long now = System.currentTimeMillis();
 
@@ -7612,9 +7642,8 @@
         for (int i = 0; i < trimCount; i++) {
             final UriPermission perm = persisted.get(i);
 
-            if (DEBUG_URI_PERMISSION) {
-                Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
-            }
+            if (DEBUG_URI_PERMISSION) Slog.v(TAG_URI_PERMISSION,
+                    "Trimming grant created at " + perm.persistedCreateTime);
 
             perm.releasePersistableModes(~0);
             removeUriPermissionIfNeededLocked(perm);
@@ -7808,7 +7837,7 @@
         }
         if (!allowed) {
             Slog.w(TAG, caller + ": caller " + callingUid
-                    + " does not hold GET_TASKS; limiting output");
+                    + " does not hold REAL_GET_TASKS; limiting output");
         }
         return allowed;
     }
@@ -7844,7 +7873,7 @@
                 TaskRecord tr = mRecentTasks.get(i);
                 // Only add calling user or related users recent tasks
                 if (!includedUsers.contains(Integer.valueOf(tr.userId))) {
-                    if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not user: " + tr);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
                     continue;
                 }
 
@@ -7863,25 +7892,27 @@
                         // If the caller doesn't have the GET_TASKS permission, then only
                         // allow them to see a small subset of tasks -- their own and home.
                         if (!tr.isHomeTask() && tr.effectiveUid != callingUid) {
-                            if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, not allowed: " + tr);
+                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
                             continue;
                         }
                     }
                     if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
                         if (tr.stack != null && tr.stack.isHomeStack()) {
-                            if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, home stack task: " + tr);
+                            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                    "Skipping, home stack task: " + tr);
                             continue;
                         }
                     }
                     if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
                         // Don't include auto remove tasks that are finished or finishing.
-                        if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, auto-remove without activity: "
-                                + tr);
+                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                "Skipping, auto-remove without activity: " + tr);
                         continue;
                     }
                     if ((flags&ActivityManager.RECENT_IGNORE_UNAVAILABLE) != 0
                             && !tr.isAvailable) {
-                        if (DEBUG_RECENTS) Slog.d(TAG, "Skipping, unavail real act: " + tr);
+                        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                                "Skipping, unavail real act: " + tr);
                         continue;
                     }
 
@@ -8215,10 +8246,9 @@
      */
     @Override
     public void moveTaskToFront(int taskId, int flags, Bundle options) {
-        enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
-                "moveTaskToFront()");
+        enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()");
 
-        if (DEBUG_STACK) Slog.d(TAG, "moveTaskToFront: moving taskId=" + taskId);
+        if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToFront: moving taskId=" + taskId);
         synchronized(this) {
             moveTaskToFrontLocked(taskId, flags, options);
         }
@@ -8378,8 +8408,8 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (DEBUG_STACK) Slog.d(TAG, "moveTaskToStack: moving task=" + taskId + " to stackId="
-                        + stackId + " toTop=" + toTop);
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
+                        + " to stackId=" + stackId + " toTop=" + toTop);
                 mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -8451,52 +8481,54 @@
         }
     }
 
-    private boolean isLockTaskAuthorized(String pkg) {
-        final DevicePolicyManager dpm = (DevicePolicyManager)
-                mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        try {
-            int uid = mContext.getPackageManager().getPackageUid(pkg,
-                    Binder.getCallingUserHandle().getIdentifier());
-            return (uid == Binder.getCallingUid()) && dpm != null && dpm.isLockTaskPermitted(pkg);
-        } catch (NameNotFoundException e) {
-            return false;
+    @Override
+    public void updateLockTaskPackages(int userId, String[] packages) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("updateLockTaskPackage called from non-system process");
+        }
+        synchronized (this) {
+            mLockTaskPackages.put(userId, packages);
         }
     }
 
-    void startLockTaskMode(TaskRecord task) {
-        final String pkg;
-        synchronized (this) {
-            pkg = task.intent.getComponent().getPackageName();
+    private boolean isLockTaskAuthorizedLocked(String pkg) {
+        String[] packages = mLockTaskPackages.get(mCurrentUserId);
+        if (packages == null) {
+            return false;
         }
+        for (int i = packages.length - 1; i >= 0; --i) {
+            if (pkg.equals(packages[i])) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void startLockTaskModeLocked(TaskRecord task) {
+        final String pkg = task.intent.getComponent().getPackageName();
         // isSystemInitiated is used to distinguish between locked and pinned mode, as pinned mode
         // is initiated by system after the pinning request was shown and locked mode is initiated
         // by an authorized app directly
         boolean isSystemInitiated = Binder.getCallingUid() == Process.SYSTEM_UID;
-        if (!isSystemInitiated && !isLockTaskAuthorized(pkg)) {
-            StatusBarManagerInternal statusBarManager = LocalServices.getService(
-                    StatusBarManagerInternal.class);
-            if (statusBarManager != null) {
-                statusBarManager.showScreenPinningRequest();
-            }
-            return;
-        }
         long ident = Binder.clearCallingIdentity();
         try {
-            synchronized (this) {
-                // Since we lost lock on task, make sure it is still there.
-                task = mStackSupervisor.anyTaskForIdLocked(task.taskId);
-                if (task != null) {
-                    if (!isSystemInitiated
-                            && ((mStackSupervisor.getFocusedStack() == null)
-                                    || (task != mStackSupervisor.getFocusedStack().topTask()))) {
-                        throw new IllegalArgumentException("Invalid task, not in foreground");
-                    }
-                    mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
-                            ActivityManager.LOCK_TASK_MODE_PINNED :
-                            ActivityManager.LOCK_TASK_MODE_LOCKED,
-                            "startLockTask");
+            if (!isSystemInitiated && !isLockTaskAuthorizedLocked(pkg)) {
+                StatusBarManagerInternal statusBarManager =
+                        LocalServices.getService(StatusBarManagerInternal.class);
+                if (statusBarManager != null) {
+                    statusBarManager.showScreenPinningRequest();
                 }
+                return;
             }
+
+            final ActivityStack stack = mStackSupervisor.getFocusedStack();
+            if (!isSystemInitiated && (stack == null || task != stack.topTask())) {
+                throw new IllegalArgumentException("Invalid task, not in foreground");
+            }
+            mStackSupervisor.setLockTaskModeLocked(task, isSystemInitiated ?
+                    ActivityManager.LOCK_TASK_MODE_PINNED :
+                    ActivityManager.LOCK_TASK_MODE_LOCKED,
+                    "startLockTask");
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -8504,37 +8536,25 @@
 
     @Override
     public void startLockTaskMode(int taskId) {
-        final TaskRecord task;
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (this) {
-                task = mStackSupervisor.anyTaskForIdLocked(taskId);
+        synchronized (this) {
+            final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+            if (task != null) {
+                startLockTaskModeLocked(task);
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-        if (task != null) {
-            startLockTaskMode(task);
         }
     }
 
     @Override
     public void startLockTaskMode(IBinder token) {
-        final TaskRecord task;
-        long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (this) {
-                final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-                if (r == null) {
-                    return;
-                }
-                task = r.task;
+        synchronized (this) {
+            final ActivityRecord r = ActivityRecord.forTokenLocked(token);
+            if (r == null) {
+                return;
             }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-        if (task != null) {
-            startLockTaskMode(task);
+            final TaskRecord task = r.task;
+            if (task != null) {
+                startLockTaskModeLocked(task);
+            }
         }
     }
 
@@ -8544,11 +8564,12 @@
                 "startLockTaskModeOnCurrent");
         long ident = Binder.clearCallingIdentity();
         try {
-            ActivityRecord r = null;
             synchronized (this) {
-                r = mStackSupervisor.topRunningActivityLocked();
+                ActivityRecord r = mStackSupervisor.topRunningActivityLocked();
+                if (r != null) {
+                    startLockTaskModeLocked(r.task);
+                }
             }
-            startLockTaskMode(r.task);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -8634,7 +8655,7 @@
                     (ProviderInfo)providers.get(i);
                 boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                         cpi.name, cpi.flags);
-                if (singleton && UserHandle.getUserId(app.uid) != 0) {
+                if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {
                     // This is a singleton provider, but a user besides the
                     // default user is asking to initialize a process it runs
                     // in...  well, no, it doesn't actually run in this process,
@@ -8790,7 +8811,7 @@
             for (int i=0; i<r.conProviders.size(); i++) {
                 ContentProviderConnection conn = r.conProviders.get(i);
                 if (conn.provider == cpr) {
-                    if (DEBUG_PROVIDER) Slog.v(TAG,
+                    if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                             "Adding provider requested by "
                             + r.processName + " from process "
                             + cpr.info.processName + ": " + cpr.name.flattenToShortString()
@@ -8826,7 +8847,7 @@
             ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
         if (conn != null) {
             cpr = conn.provider;
-            if (DEBUG_PROVIDER) Slog.v(TAG,
+            if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                     "Removing provider requested by "
                     + conn.client.processName + " from process "
                     + cpr.info.processName + ": " + cpr.name.flattenToShortString()
@@ -8954,7 +8975,7 @@
                     checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                     boolean success = updateOomAdjLocked(cpr.proc);
                     checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
-                    if (DEBUG_PROVIDER) Slog.i(TAG, "Adjust success: " + success);
+                    if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
                     // NOTE: there is still a race here where a signal could be
                     // pending on the process even though we managed to update its
                     // adj level.  Not sure what to do about this, but at least
@@ -8964,8 +8985,7 @@
                         // has been killed on us.  We need to wait for a new
                         // process to be started, and make sure its death
                         // doesn't kill our process.
-                        Slog.i(TAG,
-                                "Existing provider " + cpr.name.flattenToShortString()
+                        Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                                 + " is crashing; detaching " + r);
                         boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
                         checkTime(startTime, "getContentProviderImpl: before appDied");
@@ -9076,18 +9096,16 @@
                     return cpr.newHolder(null);
                 }
 
-                if (DEBUG_PROVIDER) {
-                    RuntimeException e = new RuntimeException("here");
-                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
-                          + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
-                }
+                if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
+                            + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
+                            + cpr.info.name + " callers=" + Debug.getCallers(6));
 
                 // This is single process, and our app is now connecting to it.
                 // See if we are already in the process of launching this
                 // provider.
                 final int N = mLaunchingProviders.size();
                 int i;
-                for (i=0; i<N; i++) {
+                for (i = 0; i < N; i++) {
                     if (mLaunchingProviders.get(i) == cpr) {
                         break;
                     }
@@ -9116,9 +9134,8 @@
                         ProcessRecord proc = getProcessRecordLocked(
                                 cpi.processName, cpr.appInfo.uid, false);
                         if (proc != null && proc.thread != null) {
-                            if (DEBUG_PROVIDER) {
-                                Slog.d(TAG, "Installing in existing process " + proc);
-                            }
+                            if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
+                                    "Installing in existing process " + proc);
                             if (!proc.pubProviders.containsKey(cpi.name)) {
                                 checkTime(startTime, "getContentProviderImpl: scheduling install");
                                 proc.pubProviders.put(cpi.name, cpr);
@@ -9723,10 +9740,14 @@
     void updateSleepIfNeededLocked() {
         if (mSleeping && !shouldSleepLocked()) {
             mSleeping = false;
+            mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
             mStackSupervisor.comeOutOfSleepIfNeededLocked();
+            updateOomAdjLocked();
         } else if (!mSleeping && shouldSleepLocked()) {
             mSleeping = true;
+            mTopProcessState = ActivityManager.PROCESS_STATE_TOP_SLEEPING;
             mStackSupervisor.goingToSleepLocked();
+            updateOomAdjLocked();
 
             // Initialize the wake times of all processes.
             checkExcessivePowerUsageLocked(false);
@@ -9833,7 +9854,7 @@
     }
 
     void logLockScreen(String msg) {
-        if (DEBUG_LOCKSCREEN) Slog.d(TAG, Debug.getCallers(2) + ":" + msg
+        if (DEBUG_LOCKSCREEN) Slog.d(TAG_LOCKSCREEN, Debug.getCallers(2) + ":" + msg
                 + " mLockScreenShown=" + lockScreenShownToString() + " mWakefulness="
                 + PowerManagerInternal.wakefulnessToString(mWakefulness)
                 + " mSleeping=" + mSleeping);
@@ -10697,7 +10718,8 @@
             for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
                 ProcessRecord proc = mLruProcesses.get(i);
                 if (proc.notCachedSinceIdle) {
-                    if (proc.setProcState > ActivityManager.PROCESS_STATE_TOP
+                    if (proc.setProcState != ActivityManager.PROCESS_STATE_TOP
+                            && proc.setProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
                             && proc.setProcState <= ActivityManager.PROCESS_STATE_SERVICE) {
                         if (doKilling && proc.initialIdlePss != 0
                                 && proc.lastPss > ((proc.initialIdlePss*3)/2)) {
@@ -12032,16 +12054,23 @@
 
     public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
         enforceNotIsolatedCaller("getRunningAppProcesses");
+
+        final int callingUid = Binder.getCallingUid();
+
         // Lazy instantiation of list
         List<ActivityManager.RunningAppProcessInfo> runList = null;
         final boolean allUsers = ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL,
-                Binder.getCallingUid()) == PackageManager.PERMISSION_GRANTED;
-        int userId = UserHandle.getUserId(Binder.getCallingUid());
+                callingUid) == PackageManager.PERMISSION_GRANTED;
+        final int userId = UserHandle.getUserId(callingUid);
+        final boolean allUids = isGetTasksAllowed(
+                "getRunningAppProcesses", Binder.getCallingPid(), callingUid);
+
         synchronized (this) {
             // Iterate across all processes
-            for (int i=mLruProcesses.size()-1; i>=0; i--) {
+            for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
                 ProcessRecord app = mLruProcesses.get(i);
-                if (!allUsers && app.userId != userId) {
+                if ((!allUsers && app.userId != userId)
+                        || (!allUids && app.uid != callingUid)) {
                     continue;
                 }
                 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
@@ -12065,7 +12094,7 @@
                     //Slog.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
                     //        + " lru=" + currApp.lru);
                     if (runList == null) {
-                        runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
+                        runList = new ArrayList<>();
                     }
                     runList.add(currApp);
                 }
@@ -12868,16 +12897,28 @@
                         + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
             }
         }
-        if (mMemWatchProcesses.size() > 0) {
+        if (mMemWatchProcesses.getMap().size() > 0) {
             pw.println("  Mem watch processes:");
-            for (int i=0; i<mMemWatchProcesses.size(); i++) {
-                if (needSep) {
-                    pw.println();
-                    needSep = false;
+            final ArrayMap<String, SparseArray<Pair<Long, String>>> procs
+                    = mMemWatchProcesses.getMap();
+            for (int i=0; i<procs.size(); i++) {
+                final String proc = procs.keyAt(i);
+                final SparseArray<Pair<Long, String>> uids = procs.valueAt(i);
+                for (int j=0; j<uids.size(); j++) {
+                    if (needSep) {
+                        pw.println();
+                        needSep = false;
+                    }
+                    StringBuilder sb = new StringBuilder();
+                    sb.append("    ").append(proc).append('/');
+                    UserHandle.formatUid(sb, uids.keyAt(j));
+                    Pair<Long, String> val = uids.valueAt(j);
+                    sb.append(": "); DebugUtils.sizeValueToString(val.first, sb);
+                    if (val.second != null) {
+                        sb.append(", report to ").append(val.second);
+                    }
+                    pw.println(sb.toString());
                 }
-                pw.print("    "); pw.print(mMemWatchProcesses.keyAt(i));
-                pw.print(": "); DebugUtils.printSizeValue(pw, mMemWatchProcesses.valueAt(i));
-                pw.println();
             }
             pw.print("  mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
             pw.print("  mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
@@ -13907,7 +13948,7 @@
             } else if ("-h".equals(opt)) {
                 pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
                 pw.println("  -a: include all available information for each process.");
-                pw.println("  -d: include dalvik details when dumping process details.");
+                pw.println("  -d: include dalvik details.");
                 pw.println("  -c: dump in a compact machine-parseable representation.");
                 pw.println("  --oom: only show processes organized by oom adj.");
                 pw.println("  --local: only collect details locally, don't call process.");
@@ -13994,6 +14035,8 @@
         final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
         long nativePss = 0;
         long dalvikPss = 0;
+        long[] dalvikSubitemPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+                EmptyArray.LONG;
         long otherPss = 0;
         long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
 
@@ -14071,6 +14114,9 @@
 
                     nativePss += mi.nativePss;
                     dalvikPss += mi.dalvikPss;
+                    for (int j=0; j<dalvikSubitemPss.length; j++) {
+                        dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+                    }
                     otherPss += mi.otherPss;
                     for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
                         long mem = mi.getOtherPss(j);
@@ -14129,6 +14175,10 @@
 
                         nativePss += mi.nativePss;
                         dalvikPss += mi.dalvikPss;
+                        for (int j=0; j<dalvikSubitemPss.length; j++) {
+                            dalvikSubitemPss[j] += mi.getOtherPss(
+                                    Debug.MemoryInfo.NUM_OTHER_STATS + j);
+                        }
                         otherPss += mi.otherPss;
                         for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
                             long mem = mi.getOtherPss(j);
@@ -14147,7 +14197,16 @@
             ArrayList<MemItem> catMems = new ArrayList<MemItem>();
 
             catMems.add(new MemItem("Native", "Native", nativePss, -1));
-            catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, -2));
+            final MemItem dalvikItem = new MemItem("Dalvik", "Dalvik", dalvikPss, -2);
+            if (dalvikSubitemPss.length > 0) {
+                dalvikItem.subitems = new ArrayList<MemItem>();
+                for (int j=0; j<dalvikSubitemPss.length; j++) {
+                    final String name = Debug.MemoryInfo.getOtherLabel(
+                            Debug.MemoryInfo.NUM_OTHER_STATS + j);
+                    dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j], j));
+                }
+            }
+            catMems.add(dalvikItem);
             catMems.add(new MemItem("Unknown", "Unknown", otherPss, -3));
             for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
                 String label = Debug.MemoryInfo.getOtherLabel(j);
@@ -14905,8 +14964,8 @@
             throw new IllegalArgumentException("File descriptors passed in Intent");
         }
 
-        if (DEBUG_SERVICE)
-            Slog.v(TAG, "startService: " + service + " type=" + resolvedType);
+        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+                "startService: " + service + " type=" + resolvedType);
         synchronized(this) {
             final int callingPid = Binder.getCallingPid();
             final int callingUid = Binder.getCallingUid();
@@ -14921,8 +14980,8 @@
     ComponentName startServiceInPackage(int uid, Intent service, String resolvedType, int userId)
             throws TransactionTooLargeException {
         synchronized(this) {
-            if (DEBUG_SERVICE)
-                Slog.v(TAG, "startServiceInPackage: " + service + " type=" + resolvedType);
+            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
+                    "startServiceInPackage: " + service + " type=" + resolvedType);
             final long origId = Binder.clearCallingIdentity();
             ComponentName res = mServices.startServiceLocked(null, service,
                     resolvedType, -1, uid, userId);
@@ -15439,8 +15498,9 @@
         }
 
         synchronized (this) {
-            if (callerApp != null && callerApp.pid == 0) {
-                // Caller already died
+            if (callerApp != null && (callerApp.thread == null
+                    || callerApp.thread.asBinder() != caller.asBinder())) {
+                // Original caller already died
                 return null;
             }
             ReceiverList rl
@@ -15581,7 +15641,7 @@
                 }
                 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                         .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
-                if (user != 0 && newReceivers != null) {
+                if (user != UserHandle.USER_OWNER && newReceivers != null) {
                     // If this is not the primary user, we need to check for
                     // any receivers that should be filtered out.
                     for (int i=0; i<newReceivers.size(); i++) {
@@ -16802,6 +16862,8 @@
 
         app.systemNoUi = false;
 
+        final int PROCESS_STATE_TOP = mTopProcessState;
+
         // Determine the importance of the process, starting with most
         // important to least, and assign an appropriate OOM adjustment.
         int adj;
@@ -16815,7 +16877,7 @@
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "top-activity";
             foregroundActivities = true;
-            procState = ActivityManager.PROCESS_STATE_TOP;
+            procState = PROCESS_STATE_TOP;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -16868,8 +16930,8 @@
                         adj = ProcessList.VISIBLE_APP_ADJ;
                         app.adjType = "visible";
                     }
-                    if (procState > ActivityManager.PROCESS_STATE_TOP) {
-                        procState = ActivityManager.PROCESS_STATE_TOP;
+                    if (procState > PROCESS_STATE_TOP) {
+                        procState = PROCESS_STATE_TOP;
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
                     app.cached = false;
@@ -16881,8 +16943,8 @@
                         adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                         app.adjType = "pausing";
                     }
-                    if (procState > ActivityManager.PROCESS_STATE_TOP) {
-                        procState = ActivityManager.PROCESS_STATE_TOP;
+                    if (procState > PROCESS_STATE_TOP) {
+                        procState = PROCESS_STATE_TOP;
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
                     app.cached = false;
@@ -16921,7 +16983,7 @@
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+                procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                 app.cached = false;
                 app.adjType = "fg-service";
                 schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -17388,11 +17450,11 @@
      * Record new PSS sample for a process.
      */
     void recordPssSampleLocked(ProcessRecord proc, int procState, long pss, long uss, long now) {
-        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss*1024, uss*1024);
+        EventLogTags.writeAmPss(proc.pid, proc.uid, proc.processName, pss * 1024, uss * 1024);
         proc.lastPssTime = now;
         proc.baseProcessTracker.addPss(pss, uss, true, proc.pkgList);
-        if (DEBUG_PSS) Slog.d(TAG, "PSS of " + proc.toShortString()
-                + ": " + pss + " lastPss=" + proc.lastPss
+        if (DEBUG_PSS) Slog.d(TAG_PSS,
+                "PSS of " + proc.toShortString() + ": " + pss + " lastPss=" + proc.lastPss
                 + " state=" + ProcessList.makeProcStateString(procState));
         if (proc.initialIdlePss == 0) {
             proc.initialIdlePss = pss;
@@ -17402,9 +17464,20 @@
             proc.lastCachedPss = pss;
         }
 
-        Long check = mMemWatchProcesses.get(proc.processName);
+        final SparseArray<Pair<Long, String>> watchUids
+                = mMemWatchProcesses.getMap().get(proc.processName);
+        Long check = null;
+        if (watchUids != null) {
+            Pair<Long, String> val = watchUids.get(proc.uid);
+            if (val == null) {
+                val = watchUids.get(0);
+            }
+            if (val != null) {
+                check = val.first;
+            }
+        }
         if (check != null) {
-            if ((pss*1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
+            if ((pss * 1024) >= check && proc.thread != null && mMemWatchDumpProcName == null) {
                 boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
                 if (!isDebuggable) {
                     if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
@@ -17434,11 +17507,13 @@
                                 fd = ParcelFileDescriptor.open(heapdumpFile,
                                         ParcelFileDescriptor.MODE_CREATE |
                                                 ParcelFileDescriptor.MODE_TRUNCATE |
-                                                ParcelFileDescriptor.MODE_READ_WRITE);
+                                                ParcelFileDescriptor.MODE_WRITE_ONLY |
+                                                ParcelFileDescriptor.MODE_APPEND);
                                 IApplicationThread thread = myProc.thread;
                                 if (thread != null) {
                                     try {
-                                        if (DEBUG_PSS) Slog.d(TAG, "Requesting dump heap from "
+                                        if (DEBUG_PSS) Slog.d(TAG_PSS,
+                                                "Requesting dump heap from "
                                                 + myProc + " to " + heapdumpFile);
                                         thread.dumpHeap(true, heapdumpFile.toString(), fd);
                                     } catch (RemoteException e) {
@@ -17474,7 +17549,7 @@
         if (mPendingPssProcesses.size() == 0) {
             mBgHandler.sendEmptyMessage(COLLECT_PSS_BG_MSG);
         }
-        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of: " + proc);
+        if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of: " + proc);
         proc.pssProcState = procState;
         mPendingPssProcesses.add(proc);
     }
@@ -17489,7 +17564,7 @@
                 return;
             }
         }
-        if (DEBUG_PSS) Slog.d(TAG, "Requesting PSS of all procs!  memLowered=" + memLowered);
+        if (DEBUG_PSS) Slog.d(TAG_PSS, "Requesting PSS of all procs!  memLowered=" + memLowered);
         mLastFullPssTime = now;
         mFullPssPending = true;
         mPendingPssProcesses.ensureCapacity(mLruProcesses.size());
@@ -17705,7 +17780,7 @@
                     sb.append(" (");
                     sb.append((wtimeUsed*100)/realtimeSince);
                     sb.append("%)");
-                    Slog.i(TAG, sb.toString());
+                    Slog.i(TAG_POWER, sb.toString());
                     sb.setLength(0);
                     sb.append("CPU for ");
                     app.toShortString(sb);
@@ -17716,7 +17791,7 @@
                     sb.append(" (");
                     sb.append((cputimeUsed*100)/uptimeSince);
                     sb.append("%)");
-                    Slog.i(TAG, sb.toString());
+                    Slog.i(TAG_POWER, sb.toString());
                 }
                 // If a process has held a wake lock for more
                 // than 50% of the time during this period,
@@ -17833,7 +17908,7 @@
             app.lastStateTime = now;
             app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, true,
                     mTestPssMode, isSleeping(), now);
-            if (DEBUG_PSS) Slog.d(TAG, "Process state change from "
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "Process state change from "
                     + ProcessList.makeProcStateString(app.setProcState) + " to "
                     + ProcessList.makeProcStateString(app.curProcState) + " next pss in "
                     + (app.nextPssTime-now) + ": " + app);
@@ -17844,9 +17919,8 @@
                 requestPssLocked(app, app.setProcState);
                 app.nextPssTime = ProcessList.computeNextPssTime(app.curProcState, false,
                         mTestPssMode, isSleeping(), now);
-            } else if (false && DEBUG_PSS) {
-                Slog.d(TAG, "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
-            }
+            } else if (false && DEBUG_PSS) Slog.d(TAG_PSS,
+                    "Not requesting PSS of " + app + ": next=" + (app.nextPssTime-now));
         }
         if (app.setProcState != app.curProcState) {
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
@@ -17867,6 +17941,10 @@
                 app.lastCpuTime = app.curCpuTime;
 
             }
+            // Inform UsageStats of important process state change
+            // Must be called before updating setProcState
+            maybeUpdateUsageStats(app);
+
             app.setProcState = app.curProcState;
             if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) {
                 app.notCachedSinceIdle = false;
@@ -17879,13 +17957,15 @@
         }
 
         if (changes != 0) {
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Changes in " + app + ": " + changes);
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "Changes in " + app + ": " + changes);
             int i = mPendingProcessChanges.size()-1;
             ProcessChangeItem item = null;
             while (i >= 0) {
                 item = mPendingProcessChanges.get(i);
                 if (item.pid == app.pid) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Re-using existing item: " + item);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Re-using existing item: " + item);
                     break;
                 }
                 i--;
@@ -17895,16 +17975,18 @@
                 final int NA = mAvailProcessChanges.size();
                 if (NA > 0) {
                     item = mAvailProcessChanges.remove(NA-1);
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Retreiving available item: " + item);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Retreiving available item: " + item);
                 } else {
                     item = new ProcessChangeItem();
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Allocating new item: " + item);
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                            "Allocating new item: " + item);
                 }
                 item.changes = 0;
                 item.pid = app.pid;
                 item.uid = app.info.uid;
                 if (mPendingProcessChanges.size() == 0) {
-                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG,
+                    if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
                             "*** Enqueueing dispatch processes changed!");
                     mHandler.obtainMessage(DISPATCH_PROCESSES_CHANGED).sendToTarget();
                 }
@@ -17913,8 +17995,8 @@
             item.changes |= changes;
             item.processState = app.repProcState;
             item.foregroundActivities = app.repForegroundActivities;
-            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG, "Item "
-                    + Integer.toHexString(System.identityHashCode(item))
+            if (DEBUG_PROCESS_OBSERVERS) Slog.i(TAG_PROCESS_OBSERVERS,
+                    "Item " + Integer.toHexString(System.identityHashCode(item))
                     + " " + app.toShortString() + ": changes=" + item.changes
                     + " procState=" + item.processState
                     + " foreground=" + item.foregroundActivities
@@ -17925,6 +18007,28 @@
         return success;
     }
 
+    private void maybeUpdateUsageStats(ProcessRecord app) {
+        if (DEBUG_USAGE_STATS) {
+            Slog.d(TAG, "Checking proc [" + Arrays.toString(app.getPackageList())
+                    + "] state changes: old = " + app.setProcState + ", new = "
+                    + app.curProcState);
+        }
+        if (mUsageStatsService == null) {
+            return;
+        }
+        if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                && (app.setProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
+                        || app.setProcState < 0)) {
+            String[] packages = app.getPackageList();
+            if (packages != null) {
+                for (int i = 0; i < packages.length; i++) {
+                    mUsageStatsService.reportEvent(packages[i], app.userId,
+                            UsageEvents.Event.INTERACTION);
+                }
+            }
+        }
+    }
+
     private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) {
         if (proc.thread != null) {
             if (proc.baseProcessTracker != null) {
@@ -18644,15 +18748,38 @@
     }
 
     @Override
-    public void setDumpHeapDebugLimit(String processName, long maxMemSize) {
-        enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
-                "setDumpHeapDebugLimit()");
+    public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
+            String reportPackage) {
+        if (processName != null) {
+            enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
+                    "setDumpHeapDebugLimit()");
+        } else {
+            if (!Build.IS_DEBUGGABLE) {
+                throw new SecurityException("Not running a debuggable build");
+            }
+            synchronized (mPidsSelfLocked) {
+                ProcessRecord proc = mPidsSelfLocked.get(Binder.getCallingPid());
+                if (proc == null) {
+                    throw new SecurityException("No process found for calling pid "
+                            + Binder.getCallingPid());
+                }
+                processName = proc.processName;
+                uid = proc.uid;
+                if (reportPackage != null && !proc.pkgList.containsKey(reportPackage)) {
+                    throw new SecurityException("Package " + reportPackage + " is not running in "
+                            + proc);
+                }
+            }
+        }
         synchronized (this) {
             if (maxMemSize > 0) {
-                mMemWatchProcesses.put(processName, maxMemSize);
-                mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
+                mMemWatchProcesses.put(processName, uid, new Pair(maxMemSize, reportPackage));
             } else {
-                mMemWatchProcesses.remove(processName);
+                if (uid != 0) {
+                    mMemWatchProcesses.remove(processName, uid);
+                } else {
+                    mMemWatchProcesses.getMap().remove(processName);
+                }
             }
         }
     }
@@ -18670,7 +18797,7 @@
                         + " does not match last path " + mMemWatchDumpFile);
                 return;
             }
-            if (DEBUG_PSS) Slog.d(TAG, "Dump heap finished for " + path);
+            if (DEBUG_PSS) Slog.d(TAG_PSS, "Dump heap finished for " + path);
             mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
         }
     }
@@ -19215,7 +19342,7 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        if (userId <= 0) {
+        if (userId < 0 || userId == UserHandle.USER_OWNER) {
             throw new IllegalArgumentException("Can't stop primary user " + userId);
         }
         enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
@@ -19461,14 +19588,6 @@
         mUserSwitchObservers.unregister(observer);
     }
 
-    private boolean userExists(int userId) {
-        if (userId == 0) {
-            return true;
-        }
-        UserManagerService ums = getUserManagerLocked();
-        return ums != null ? (ums.getUserInfo(userId) != null) : false;
-    }
-
     int[] getUsersLocked() {
         UserManagerService ums = getUserManagerLocked();
         return ums != null ? ums.getUserIds() : new int[] { 0 };
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index d34b33b..f3b18f5 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -17,8 +17,6 @@
 package com.android.server.am;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_THUMBNAILS;
 import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
 import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
@@ -75,6 +73,8 @@
  */
 final class ActivityRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_THUMBNAILS = TAG + POSTFIX_THUMBNAILS;
 
     private static final boolean SHOW_ACTIVITY_START_TIME = true;
     static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
@@ -354,7 +354,7 @@
             synchronized (mService) {
                 ActivityRecord r = tokenToActivityRecordLocked(this);
                 if (r != null) {
-                    if (DEBUG_SWITCH) Log.v(TAG, "windowsGone(): " + r);
+                    if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + r);
                     r.nowVisible = false;
                     return;
                 }
@@ -863,7 +863,7 @@
 
     void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
         if (newThumbnail != null) {
-            if (DEBUG_THUMBNAILS) Slog.i(TAG,
+            if (DEBUG_THUMBNAILS) Slog.i(TAG_THUMBNAILS,
                     "Setting thumbnail of " + this + " to " + newThumbnail);
             boolean thumbnailUpdated = task.setLastThumbnail(newThumbnail);
             if (thumbnailUpdated && isPersistable()) {
@@ -1014,7 +1014,7 @@
 
     void windowsVisibleLocked() {
         mStackSupervisor.reportActivityVisibleLocked(this);
-        if (DEBUG_SWITCH) Log.v(TAG, "windowsVisibleLocked(): " + this);
+        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
         if (!nowVisible) {
             nowVisible = true;
             lastVisibleTime = SystemClock.uptimeMillis();
@@ -1030,7 +1030,7 @@
                 if (size > 0) {
                     for (int i = 0; i < size; i++) {
                         ActivityRecord r = mStackSupervisor.mWaitingVisibleActivities.get(i);
-                        if (DEBUG_SWITCH) Log.v(TAG, "Was waiting for visible: " + r);
+                        if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
                     }
                     mStackSupervisor.mWaitingVisibleActivities.clear();
                     mStackSupervisor.scheduleIdleLocked();
@@ -1041,24 +1041,21 @@
     }
 
     ActivityRecord getWaitingHistoryRecordLocked() {
-        // First find the real culprit...  if we are waiting
-        // for another app to start, then we have paused dispatching
-        // for this activity.
-        ActivityRecord r = this;
-        if (mStackSupervisor.mWaitingVisibleActivities.contains(this)) {
+        // First find the real culprit...  if this activity is waiting for
+        // another activity to start or has stopped, then the key dispatching
+        // timeout should not be caused by this.
+        if (mStackSupervisor.mWaitingVisibleActivities.contains(this) || stopped) {
             final ActivityStack stack = mStackSupervisor.getFocusedStack();
-            // Hmmm, who might we be waiting for?
-            r = stack.mResumedActivity;
+            // Try to use the one which is closest to top.
+            ActivityRecord r = stack.mResumedActivity;
             if (r == null) {
                 r = stack.mPausingActivity;
             }
-            // Both of those null?  Fall back to 'this' again
-            if (r == null) {
-                r = this;
+            if (r != null) {
+                return r;
             }
         }
-
-        return r;
+        return this;
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 8ba34e2..2362d28 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -16,15 +16,9 @@
 
 package com.android.server.am;
 
+import static android.content.pm.ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
+
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TRANSITION;
-import static com.android.server.am.ActivityManagerService.DEBUG_USER_LEAVING;
-import static com.android.server.am.ActivityManagerService.DEBUG_VISBILITY;
 
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
@@ -96,6 +90,14 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_AM;
     private static final String TAG_CLEANUP = TAG + POSTFIX_CLEANUP;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
+    private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+    private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
+    private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
 
     private static final boolean VALIDATE_TOKENS = false;
 
@@ -373,8 +375,7 @@
     }
 
     boolean okToShowLocked(ActivityRecord r) {
-        return isCurrentProfileLocked(r.userId)
-                || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
+        return isCurrentProfileLocked(r.userId) || (r.info.flags & FLAG_SHOW_ON_LOCK_SCREEN) != 0;
     }
 
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
@@ -538,23 +539,23 @@
         // If documentData is non-null then it must match the existing task data.
         Uri documentData = isDocument ? intent.getData() : null;
 
-        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
+        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             if (task.voiceSession != null) {
                 // We never match voice sessions; those always run independently.
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": voice session");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
                 continue;
             }
             if (task.userId != userId) {
                 // Looking for a different task.
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": different user");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
                 continue;
             }
             final ActivityRecord r = task.getTopActivity();
             if (r == null || r.finishing || r.userId != userId ||
                     r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Skipping " + task + ": mismatch root " + r);
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
                 continue;
             }
 
@@ -573,34 +574,32 @@
                 taskDocumentData = null;
             }
 
-            if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls="
+            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
                     + taskIntent.getComponent().flattenToShortString()
                     + "/aff=" + r.task.rootAffinity + " to new cls="
                     + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
             if (!isDocument && !taskIsDocument && task.rootAffinity != null) {
                 if (task.rootAffinity.equals(target.taskAffinity)) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity!");
                     return r;
                 }
             } else if (taskIntent != null && taskIntent.getComponent() != null &&
                     taskIntent.getComponent().compareTo(cls) == 0 &&
                     Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                 //dump();
-                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
-                        + r.intent);
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                        "For Intent " + intent + " bringing to top: " + r.intent);
                 return r;
             } else if (affinityIntent != null && affinityIntent.getComponent() != null &&
                     affinityIntent.getComponent().compareTo(cls) == 0 &&
                     Objects.equals(documentData, taskDocumentData)) {
-                if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
                 //dump();
-                if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
-                        + r.intent);
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                        "For Intent " + intent + " bringing to top: " + r.intent);
                 return r;
-            } else if (DEBUG_TASKS) {
-                Slog.d(TAG, "Not a match: " + task);
-            }
+            } else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
         }
 
         return null;
@@ -619,13 +618,15 @@
         final int userId = UserHandle.getUserId(info.applicationInfo.uid);
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
-            TaskRecord task = mTaskHistory.get(taskNdx);
-            if (!isCurrentProfileLocked(task.userId)) {
-                return null;
-            }
+            final TaskRecord task = mTaskHistory.get(taskNdx);
+            final boolean notCurrentUserTask = !isCurrentProfileLocked(task.userId);
             final ArrayList<ActivityRecord> activities = task.mActivities;
+
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = activities.get(activityNdx);
+                if (notCurrentUserTask && (r.info.flags & FLAG_SHOW_ON_LOCK_SCREEN) == 0) {
+                    return null;
+                }
                 if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) {
                     //Slog.i(TAG, "Found matching class!");
                     //dump();
@@ -650,9 +651,13 @@
         // Move userId's tasks to the top.
         int index = mTaskHistory.size();
         for (int i = 0; i < index; ) {
-            TaskRecord task = mTaskHistory.get(i);
-            if (isCurrentProfileLocked(task.userId)) {
-                if (DEBUG_TASKS) Slog.d(TAG, "switchUserLocked: stack=" + getStackId() +
+            final TaskRecord task = mTaskHistory.get(i);
+
+            // NOTE: If {@link TaskRecord#topRunningActivityLocked} return is not null then it is
+            // okay to show the activity when locked.
+            if (isCurrentProfileLocked(task.userId)
+                    || task.topRunningActivityLocked(null) != null) {
+                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUserLocked: stack=" + getStackId() +
                         " moving " + task + " to top");
                 mTaskHistory.remove(i);
                 mTaskHistory.add(task);
@@ -739,14 +744,15 @@
     boolean checkReadyForSleepLocked() {
         if (mResumedActivity != null) {
             // Still have something resumed; can't sleep until it is paused.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Sleep needs to pause " + mResumedActivity);
-            if (DEBUG_USER_LEAVING) Slog.v(TAG, "Sleep => pause with userLeaving=false");
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep needs to pause " + mResumedActivity);
+            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                    "Sleep => pause with userLeaving=false");
             startPausingLocked(false, true, false, false);
             return true;
         }
         if (mPausingActivity != null) {
             // Still waiting for something to pause; can't sleep yet.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still waiting to pause " + mPausingActivity);
             return true;
         }
 
@@ -829,7 +835,7 @@
         }
 
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
-        else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
+        else if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Start pausing: " + prev);
         mResumedActivity = null;
         mPausingActivity = prev;
         mLastPausedActivity = prev;
@@ -847,7 +853,7 @@
         mService.updateCpuStats();
 
         if (prev.app != null && prev.app.thread != null) {
-            if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
             try {
                 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                         prev.userId, System.identityHashCode(prev),
@@ -881,8 +887,8 @@
             // key dispatch; the same activity will pick it up again on wakeup.
             if (!uiSleeping) {
                 prev.pauseKeyDispatchingLocked();
-            } else {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
+            } else if (DEBUG_PAUSE) {
+                 Slog.v(TAG_PAUSE, "Key dispatch not paused for screen off");
             }
 
             if (dontWait) {
@@ -899,14 +905,14 @@
                 msg.obj = prev;
                 prev.pauseTime = SystemClock.uptimeMillis();
                 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
-                if (DEBUG_PAUSE) Slog.v(TAG, "Waiting for pause to complete...");
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete...");
                 return true;
             }
 
         } else {
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
             if (!resuming) {
                 mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
             }
@@ -915,8 +921,8 @@
     }
 
     final void activityPausedLocked(IBinder token, boolean timeout) {
-        if (DEBUG_PAUSE) Slog.v(
-            TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
+        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+            "Activity paused: token=" + token + ", timeout=" + timeout);
 
         final ActivityRecord r = isInStackLocked(token);
         if (r != null) {
@@ -930,6 +936,11 @@
                         r.userId, System.identityHashCode(r), r.shortComponentName,
                         mPausingActivity != null
                             ? mPausingActivity.shortComponentName : "(none)");
+                if (r.finishing && r.state == ActivityState.PAUSING) {
+                    if (DEBUG_PAUSE) Slog.v(TAG,
+                            "Executing finish of failed to pause activity: " + r);
+                    finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+                }
             }
         }
     }
@@ -977,18 +988,18 @@
 
     private void completePauseLocked(boolean resumeNext) {
         ActivityRecord prev = mPausingActivity;
-        if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
+        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Complete pause: " + prev);
 
         if (prev != null) {
             prev.state = ActivityState.PAUSED;
             if (prev.finishing) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false);
             } else if (prev.app != null) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending stop: " + prev);
                 if (mStackSupervisor.mWaitingVisibleActivities.remove(prev)) {
-                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
-                            TAG, "Complete pause, no longer waiting: " + prev);
+                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(TAG_PAUSE,
+                            "Complete pause, no longer waiting: " + prev);
                 }
                 if (prev.configDestroy) {
                     // The previous is being paused because the configuration
@@ -996,7 +1007,7 @@
                     // To juggle the fact that we are also starting a new
                     // instance right now, we need to first completely stop
                     // the current instance before starting the new one.
-                    if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
+                    if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Destroying after pause: " + prev);
                     destroyActivityLocked(prev, true, "pause-config");
                 } else if (!hasVisibleBehindActivity()) {
                     // If we were visible then resumeTopActivities will release resources before
@@ -1008,14 +1019,14 @@
                         // then give up on things going idle and start clearing
                         // them out. Or if r is the last of activity of the last task the stack
                         // will be empty and must be cleared immediately.
-                        if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
+                        if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "To many pending stops, forcing idle");
                         mStackSupervisor.scheduleIdleLocked();
                     } else {
                         mStackSupervisor.checkReadyForSleepLocked();
                     }
                 }
             } else {
-                if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "App died during pause, not stopping: " + prev);
                 prev = null;
             }
             // It is possible the activity was freezing the screen before it was paused.
@@ -1246,15 +1257,10 @@
         if (top == null) {
             return;
         }
-        if (DEBUG_VISBILITY) Slog.v(
-                TAG, "ensureActivitiesVisible behind " + top
+        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                "ensureActivitiesVisible behind " + top
                 + " configChanges=0x" + Integer.toHexString(configChanges));
 
-        if (DEBUG_STATES && starting != null && starting.task.stack == this) {
-            Slog.d(TAG, "ensureActivitiesVisibleLocked: starting=" + starting + " state="
-                    + starting.state + " fullscreen=" + starting.fullscreen + " top=" + top
-                    + " state=" + top.state + " fullscreen=" + top.fullscreen);
-        }
         if (mTranslucentActivityWaiting != top) {
             mUndrawnActivitiesBelowTopTranslucent.clear();
             if (mTranslucentActivityWaiting != null) {
@@ -1269,6 +1275,7 @@
         // make sure any activities under it are now visible.
         boolean aboveTop = true;
         boolean behindFullscreen = !isStackVisibleLocked();
+        boolean noStackActivityResumed = (isInStackLocked(starting) == null);
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1285,8 +1292,8 @@
                 // mLaunchingBehind: Activities launching behind are at the back of the task stack
                 // but must be drawn initially for the animation as though they were visible.
                 if (!behindFullscreen || r.mLaunchTaskBehind) {
-                    if (DEBUG_VISBILITY) Slog.v(
-                            TAG, "Make visible? " + r + " finishing=" + r.finishing
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                            "Make visible? " + r + " finishing=" + r.finishing
                             + " state=" + r.state);
 
                     // First: if this is not the current activity being started, make
@@ -1296,26 +1303,29 @@
                     }
 
                     if (r.app == null || r.app.thread == null) {
-                        // This activity needs to be visible, but isn't even
-                        // running...  get it started, but don't resume it
-                        // at this point.
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Start and freeze screen for " + r);
+                        // This activity needs to be visible, but isn't even running...
+                        // get it started and resume if no other stack in this stack is resumed.
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                "Start and freeze screen for " + r);
                         if (r != starting) {
                             r.startFreezingScreenLocked(r.app, configChanges);
                         }
                         if (!r.visible || r.mLaunchTaskBehind) {
-                            if (DEBUG_VISBILITY) Slog.v(
-                                    TAG, "Starting and making visible: " + r);
+                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                    "Starting and making visible: " + r);
                             setVisible(r, true);
                         }
                         if (r != starting) {
-                            mStackSupervisor.startSpecificActivityLocked(r, false, false);
+                            mStackSupervisor.startSpecificActivityLocked(
+                                    r, noStackActivityResumed, false);
+                            noStackActivityResumed = false;
                         }
 
                     } else if (r.visible) {
                         // If this activity is already visible, then there is nothing
                         // else to do here.
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Skipping: already visible at " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                "Skipping: already visible at " + r);
                         r.stopFreezingScreenLocked(false);
                         try {
                             if (r.returningOptions != null) {
@@ -1331,8 +1341,8 @@
                         if (r.state != ActivityState.RESUMED && r != starting) {
                             // If this activity is paused, tell it
                             // to now show its window.
-                            if (DEBUG_VISBILITY) Slog.v(
-                                    TAG, "Making visible and scheduling visibility: " + r);
+                            if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                    "Making visible and scheduling visibility: " + r);
                             try {
                                 if (mTranslucentActivityWaiting != null) {
                                     r.updateOptionsLocked(r.returningOptions);
@@ -1357,29 +1367,28 @@
 
                     if (r.fullscreen) {
                         // At this point, nothing else needs to be shown
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Fullscreen: at " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Fullscreen: at " + r);
                         behindFullscreen = true;
                     } else if (!isHomeStack() && r.frontOfTask && task.isOverHomeStack()) {
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Showing home: at " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Showing home: at " + r);
                         behindFullscreen = true;
                     }
                 } else {
-                    if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Make invisible? " + r + " finishing=" + r.finishing
-                        + " state=" + r.state
-                        + " behindFullscreen=" + behindFullscreen);
+                    if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                        "Make invisible? " + r + " finishing=" + r.finishing
+                        + " state=" + r.state + " behindFullscreen=" + behindFullscreen);
                     // Now for any activities that aren't visible to the user, make
                     // sure they no longer are keeping the screen frozen.
                     if (r.visible) {
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Making invisible: " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r);
                         try {
                             setVisible(r, false);
                             switch (r.state) {
                                 case STOPPING:
                                 case STOPPED:
                                     if (r.app != null && r.app.thread != null) {
-                                        if (DEBUG_VISBILITY) Slog.v(
-                                                TAG, "Scheduling invisibility: " + r);
+                                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                                                "Scheduling invisibility: " + r);
                                         r.app.thread.scheduleWindowVisibility(r.appToken, false);
                                     }
                                     break;
@@ -1410,7 +1419,7 @@
                                     + r.intent.getComponent(), e);
                         }
                     } else {
-                        if (DEBUG_VISBILITY) Slog.v(TAG, "Already invisible: " + r);
+                        if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + r);
                     }
                 }
             }
@@ -1480,7 +1489,8 @@
                 }
 
                 if (r.state == ActivityState.INITIALIZING && r.mStartingWindowShown) {
-                    if (DEBUG_VISBILITY) Slog.w(TAG, "Found orphaned starting window " + r);
+                    if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY,
+                            "Found orphaned starting window " + r);
                     r.mStartingWindowShown = false;
                     mWindowManager.removeAppStartingWindow(r.appToken);
                 }
@@ -1523,7 +1533,7 @@
     }
 
     private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
-        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+        if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
         if (!mService.mBooting && !mService.mBooted) {
             // Not ready yet!
@@ -1641,12 +1651,12 @@
         next.sleeping = false;
         mStackSupervisor.mWaitingVisibleActivities.remove(next);
 
-        if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next);
 
         // If we are currently pausing an activity, then don't do anything
         // until that is done.
         if (!mStackSupervisor.allPausedActivitiesComplete()) {
-            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG,
+            if (DEBUG_SWITCH || DEBUG_PAUSE || DEBUG_STATES) Slog.v(TAG_PAUSE,
                     "resumeTopActivityLocked: Skip resume: some activity pausing.");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
             return false;
@@ -1721,8 +1731,8 @@
             if (!mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                     && next != null && !next.nowVisible) {
                 mStackSupervisor.mWaitingVisibleActivities.add(prev);
-                if (DEBUG_SWITCH) Slog.v(
-                        TAG, "Resuming top, waiting visible to hide: " + prev);
+                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                        "Resuming top, waiting visible to hide: " + prev);
             } else {
                 // The next activity is already visible, so hide the previous
                 // activity's windows right now so we can show the new one ASAP.
@@ -1734,16 +1744,16 @@
                 // new one is found to be full-screen or not.
                 if (prev.finishing) {
                     mWindowManager.setAppVisibility(prev.appToken, false);
-                    if (DEBUG_SWITCH) Slog.v(TAG, "Not waiting for visible to hide: "
-                            + prev + ", waitingVisible="
+                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                            "Not waiting for visible to hide: " + prev + ", waitingVisible="
                             + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
                             + ", nowVisible=" + next.nowVisible);
                 } else {
-                    if (DEBUG_SWITCH) Slog.v(TAG,
+                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
                             "Previous already visible but still waiting to hide: " + prev
-                                    + ", waitingVisible="
-                                    + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
-                                    + ", nowVisible=" + next.nowVisible);
+                            + ", waitingVisible="
+                            + mStackSupervisor.mWaitingVisibleActivities.contains(prev)
+                            + ", nowVisible=" + next.nowVisible);
                 }
             }
         }
@@ -1765,7 +1775,7 @@
         boolean anim = true;
         if (prev != null) {
             if (prev.finishing) {
-                if (DEBUG_TRANSITION) Slog.v(TAG,
+                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                         "Prepare close transition: prev=" + prev);
                 if (mNoAnimActivities.contains(prev)) {
                     anim = false;
@@ -1778,7 +1788,8 @@
                 mWindowManager.setAppWillBeHidden(prev.appToken);
                 mWindowManager.setAppVisibility(prev.appToken, false);
             } else {
-                if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: prev=" + prev);
+                if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
+                        "Prepare open transition: prev=" + prev);
                 if (mNoAnimActivities.contains(next)) {
                     anim = false;
                     mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -1795,7 +1806,7 @@
                 mWindowManager.setAppVisibility(prev.appToken, false);
             }
         } else {
-            if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare open transition: no previous");
+            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
             if (mNoAnimActivities.contains(next)) {
                 anim = false;
                 mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
@@ -1817,7 +1828,7 @@
 
         ActivityStack lastStack = mStackSupervisor.getLastStack();
         if (next.app != null && next.app.thread != null) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Resume running: " + next);
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next);
 
             // This activity is now becoming visible.
             mWindowManager.setAppVisibility(next.appToken, true);
@@ -1882,9 +1893,8 @@
                 if (a != null) {
                     final int N = a.size();
                     if (!next.finishing && N > 0) {
-                        if (DEBUG_RESULTS) Slog.v(
-                                TAG, "Delivering results to " + next
-                                + ": " + a);
+                        if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+                                "Delivering results to " + next + ": " + a);
                         next.app.thread.scheduleSendResult(next.appToken, a);
                     }
                 }
@@ -1899,7 +1909,7 @@
                 next.sleeping = false;
                 mService.showAskCompatModeDialogLocked(next);
                 next.app.pendingUiClean = true;
-                next.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
+                next.app.forceProcessStateUpTo(mService.mTopProcessState);
                 next.clearOptionsLocked();
                 next.app.thread.scheduleResumeActivity(next.appToken, next.app.repProcState,
                         mService.isNextTransitionForward(), resumeAnimOptions);
@@ -1961,7 +1971,7 @@
                             next.labelRes, next.icon, next.logo, next.windowFlags,
                             null, true);
                 }
-                if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next);
+                if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next);
             }
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Restarting " + next);
             mStackSupervisor.startSpecificActivityLocked(next, true, true);
@@ -1985,7 +1995,7 @@
         return null;
     }
 
-    private void insertTaskAtTop(TaskRecord task) {
+    private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
         // If the moving task is over home stack, transfer its return type to next task
         if (task.isOverHomeStack()) {
             final TaskRecord nextTask = getNextTask(task);
@@ -2013,10 +2023,15 @@
         mTaskHistory.remove(task);
         // Now put task at top.
         int taskNdx = mTaskHistory.size();
-        if (!isCurrentProfileLocked(task.userId)) {
+        final boolean notShownWhenLocked =
+                (newActivity != null && (newActivity.info.flags & FLAG_SHOW_ON_LOCK_SCREEN) == 0)
+                || (newActivity == null && task.topRunningActivityLocked(null) == null);
+        if (!isCurrentProfileLocked(task.userId) && notShownWhenLocked) {
             // Put non-current user tasks below current user tasks.
             while (--taskNdx >= 0) {
-                if (!isCurrentProfileLocked(mTaskHistory.get(taskNdx).userId)) {
+                final TaskRecord tmpTask = mTaskHistory.get(taskNdx);
+                if (!isCurrentProfileLocked(tmpTask.userId)
+                        || tmpTask.topRunningActivityLocked(null) == null) {
                     break;
                 }
             }
@@ -2035,7 +2050,7 @@
             // Last activity in task had been removed or ActivityManagerService is reusing task.
             // Insert or replace.
             // Might not even be in.
-            insertTaskAtTop(rTask);
+            insertTaskAtTop(rTask, r);
             mWindowManager.moveTaskToTop(taskId);
         }
         TaskRecord task = null;
@@ -2083,7 +2098,7 @@
         // activity
         if (task == r.task && mTaskHistory.indexOf(task) != (mTaskHistory.size() - 1)) {
             mStackSupervisor.mUserLeaving = false;
-            if (DEBUG_USER_LEAVING) Slog.v(TAG,
+            if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                     "startActivity() behind front, mUserLeaving=false");
         }
 
@@ -2108,9 +2123,9 @@
             if (proc == null || proc.thread == null) {
                 showStartingIcon = true;
             }
-            if (DEBUG_TRANSITION) Slog.v(TAG,
+            if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare open transition: starting " + r);
-            if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
                 mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition);
                 mNoAnimActivities.add(r);
             } else {
@@ -2280,13 +2295,13 @@
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
                     targetTask = bottom.task;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to bottom task " + bottom.task);
                 } else {
                     targetTask = createTaskRecord(mStackSupervisor.getNextTaskId(), target.info,
                             null, null, null, false);
                     targetTask.affinityIntent = target.intent;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Start pushing activity " + target
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to new task " + target.task);
                 }
 
@@ -2311,8 +2326,8 @@
                     if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing activity " + p + " from task="
                             + task + " adding to task=" + targetTask
                             + " Callers=" + Debug.getCallers(4));
-                    if (DEBUG_TASKS) Slog.v(TAG, "Pushing next activity " + p
-                            + " out to target's task " + target.task);
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                            "Pushing next activity " + p + " out to target's task " + target.task);
                     p.setTask(targetTask, null);
                     targetTask.addActivityAtBottom(p);
 
@@ -2354,7 +2369,7 @@
                             noOptions = false;
                         }
                     }
-                    if (DEBUG_TASKS) Slog.w(TAG,
+                    if (DEBUG_TASKS) Slog.w(TAG_TASKS,
                             "resetTaskIntendedTask: calling finishActivity on " + p);
                     if (finishActivityLocked(
                             p, Activity.RESULT_CANCELED, null, "reset-task", false)) {
@@ -2428,7 +2443,8 @@
                 // in a task that is not currently on top.)
                 if (forceReset || finishOnTaskLaunch) {
                     final int start = replyChainEnd >= 0 ? replyChainEnd : i;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Finishing task at index " + start + " to " + i);
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                            "Finishing task at index " + start + " to " + i);
                     for (int srcPos = start; srcPos >= i; --srcPos) {
                         final ActivityRecord p = activities.get(srcPos);
                         if (p.finishing) {
@@ -2444,8 +2460,9 @@
                     }
 
                     final int start = replyChainEnd >= 0 ? replyChainEnd : i;
-                    if (DEBUG_TASKS) Slog.v(TAG, "Reparenting from task=" + affinityTask + ":"
-                            + start + "-" + i + " to task=" + task + ":" + taskInsertionPoint);
+                    if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                            "Reparenting from task=" + affinityTask + ":" + start + "-" + i
+                            + " to task=" + task + ":" + taskInsertionPoint);
                     for (int srcPos = start; srcPos >= i; --srcPos) {
                         final ActivityRecord p = activities.get(srcPos);
                         p.setTask(task, null);
@@ -2454,8 +2471,8 @@
                         if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + p
                                 + " to stack at " + task,
                                 new RuntimeException("here").fillInStackTrace());
-                        if (DEBUG_TASKS) Slog.v(TAG, "Pulling activity " + p + " from " + srcPos
-                                + " in to resetting task " + task);
+                        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
+                                + " from " + srcPos + " in to resetting task " + task);
                         mWindowManager.setAppTask(p.appToken, taskId);
                     }
                     mWindowManager.moveTaskToTop(taskId);
@@ -2613,7 +2630,7 @@
     }
 
     final void stopActivityLocked(ActivityRecord r) {
-        if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + r);
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
             if (!r.finishing) {
@@ -2638,8 +2655,8 @@
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
                         + " (stop requested)");
                 r.state = ActivityState.STOPPING;
-                if (DEBUG_VISBILITY) Slog.v(
-                        TAG, "Stopping visible=" + r.visible + " for " + r);
+                if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
+                        "Stopping visible=" + r.visible + " for " + r);
                 if (!r.visible) {
                     mWindowManager.setAppVisibility(r.appToken, false);
                 }
@@ -2776,7 +2793,7 @@
         // send the result
         ActivityRecord resultTo = r.resultTo;
         if (resultTo != null) {
-            if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
+            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Adding result to " + resultTo
                     + " who=" + r.resultWho + " req=" + r.requestCode
                     + " res=" + resultCode + " data=" + resultData);
             if (resultTo.userId != r.userId) {
@@ -2793,7 +2810,7 @@
                                      resultData);
             r.resultTo = null;
         }
-        else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
+        else if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "No result destination from " + r);
 
         // Make sure this HistoryRecord is not holding on to other resources,
         // because clients have remote IPC references to this object so we
@@ -2841,7 +2858,7 @@
 
         if (mResumedActivity == r) {
             boolean endTask = index <= 0;
-            if (DEBUG_VISBILITY || DEBUG_TRANSITION) Slog.v(TAG,
+            if (DEBUG_VISIBILITY || DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
                     "Prepare close transition: finishing " + r);
             mWindowManager.prepareAppTransition(endTask
                     ? AppTransition.TRANSIT_TASK_CLOSE
@@ -2851,8 +2868,9 @@
             mWindowManager.setAppVisibility(r.appToken, false);
 
             if (mPausingActivity == null) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
-                if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + r);
+                if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                        "finish() => pause with userLeaving=false");
                 startPausingLocked(false, false, false, false);
             }
 
@@ -2862,10 +2880,10 @@
         } else if (r.state != ActivityState.PAUSING) {
             // If the activity is PAUSING, we will complete the finish once
             // it is done pausing; else we can just directly finish it here.
-            if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish not pausing: " + r);
             return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
-            if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
+            if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
         }
 
         return false;
@@ -3160,7 +3178,7 @@
         }
         final TaskRecord task = r.task;
         if (task != null && task.removeActivity(r)) {
-            if (DEBUG_STACK) Slog.i(TAG,
+            if (DEBUG_STACK) Slog.i(TAG_STACK,
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
             if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
                     task.isOverHomeStack()) {
@@ -3213,7 +3231,7 @@
                     continue;
                 }
                 if (r.isDestroyable()) {
-                    if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
+                    if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Destroying " + r + " in state " + r.state
                             + " resumed=" + mResumedActivity
                             + " pausing=" + mPausingActivity + " for reason " + reason);
                     if (destroyActivityLocked(r, true, reason)) {
@@ -3229,8 +3247,8 @@
 
     final boolean safelyDestroyActivityLocked(ActivityRecord r, String reason) {
         if (r.isDestroyable()) {
-            if (DEBUG_SWITCH) Slog.v(TAG, "Destroying " + r + " in state " + r.state
-                    + " resumed=" + mResumedActivity
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                    "Destroying " + r + " in state " + r.state + " resumed=" + mResumedActivity
                     + " pausing=" + mPausingActivity + " for reason " + reason);
             return destroyActivityLocked(r, true, reason);
         }
@@ -3288,9 +3306,9 @@
      * but then create a new client-side object for this same HistoryRecord.
      */
     final boolean destroyActivityLocked(ActivityRecord r, boolean removeFromApp, String reason) {
-        if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(
-            TAG, "Removing activity from " + reason + ": token=" + r
-              + ", app=" + (r.app != null ? r.app.processName : "(null)"));
+        if (DEBUG_SWITCH || DEBUG_CLEANUP) Slog.v(TAG_SWITCH,
+                "Removing activity from " + reason + ": token=" + r
+                + ", app=" + (r.app != null ? r.app.processName : "(null)"));
         EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
                 r.userId, System.identityHashCode(r),
                 r.task.taskId, r.shortComponentName, reason);
@@ -3322,7 +3340,7 @@
             boolean skipDestroy = false;
 
             try {
-                if (DEBUG_SWITCH) Slog.i(TAG, "Destroying: " + r);
+                if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + r);
                 r.app.thread.scheduleDestroyActivity(r.appToken, r.finishing,
                         r.configChangeFlags);
             } catch (Exception e) {
@@ -3492,6 +3510,9 @@
                 if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                         "Record #" + i + " " + r + ": app=" + r.app);
                 if (r.app == app) {
+                    if (r.visible) {
+                        hasVisibleActivities = true;
+                    }
                     final boolean remove;
                     if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
                         // Don't currently have state for the activity, or
@@ -3531,9 +3552,6 @@
                         // it can be restarted later when needed.
                         if (DEBUG_ALL) Slog.v(
                             TAG, "Keeping entry, setting app to null");
-                        if (r.visible) {
-                            hasVisibleActivities = true;
-                        }
                         if (DEBUG_APP) Slog.v(TAG, "Clearing app during removeHistory for activity "
                                 + r);
                         r.app = null;
@@ -3584,8 +3602,8 @@
         for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
             if (task.taskType == homeStackTaskType) {
-                if (DEBUG_TASKS || DEBUG_STACK)
-                    Slog.d(TAG, "moveHomeStackTaskToTop: moving " + task);
+                if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
+                        "moveHomeStackTaskToTop: moving " + task);
                 mTaskHistory.remove(taskNdx);
                 mTaskHistory.add(top, task);
                 updateTaskMovement(task, true);
@@ -3596,7 +3614,7 @@
 
     final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, Bundle options,
             String reason) {
-        if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
         final int numTasks = mTaskHistory.size();
         final int index = mTaskHistory.indexOf(tr);
@@ -3612,13 +3630,13 @@
 
         // Shift all activities with this task up to the top
         // of the stack, keeping them in the same internal order.
-        insertTaskAtTop(tr);
+        insertTaskAtTop(tr, null);
 
         // Set focus to the top running activity of this stack.
         ActivityRecord r = topRunningActivityLocked(null);
         mService.setFocusedActivityLocked(r, reason);
 
-        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to front transition: task=" + tr);
+        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to front transition: task=" + tr);
         if (noAnimation) {
             mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, false);
             if (r != null) {
@@ -3682,7 +3700,7 @@
             }
         }
 
-        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
+        if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
 
         boolean prevIsHome = false;
         if (tr.isOverHomeStack()) {
@@ -3912,8 +3930,8 @@
             results = r.results;
             newIntents = r.newIntents;
         }
-        if (DEBUG_SWITCH) Slog.v(TAG, "Relaunching: " + r
-                + " with results=" + results + " newIntents=" + newIntents
+        if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                "Relaunching: " + r + " with results=" + results + " newIntents=" + newIntents
                 + " andResume=" + andResume);
         EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
                 : EventLogTags.AM_RELAUNCH_ACTIVITY, r.userId, System.identityHashCode(r),
@@ -3924,8 +3942,8 @@
         mStackSupervisor.removeChildActivityContainers(r);
 
         try {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Moving to " +
-                    (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
+            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
+                    "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + r);
             r.forceNewConfig = false;
             r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
                     !andResume, new Configuration(mService.mConfiguration),
@@ -3934,7 +3952,7 @@
             // the caller will only pass in 'andResume' if this activity is
             // currently resumed, which implies we aren't sleeping.
         } catch (RemoteException e) {
-            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
+            if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
         }
 
         if (andResume) {
@@ -4035,16 +4053,18 @@
     }
 
     void getTasksLocked(List<RunningTaskInfo> list, int callingUid, boolean allowed) {
+        boolean focusedStack = mStackSupervisor.getFocusedStack() == this;
+        boolean topTask = true;
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
+            if (task.getTopActivity() == null) {
+                continue;
+            }
             ActivityRecord r = null;
             ActivityRecord top = null;
             int numActivities = 0;
             int numRunning = 0;
             final ArrayList<ActivityRecord> activities = task.mActivities;
-            if (activities.isEmpty()) {
-                continue;
-            }
             if (!allowed && !task.isHomeTask() && task.effectiveUid != callingUid) {
                 continue;
             }
@@ -4073,22 +4093,25 @@
             ci.baseActivity = r.intent.getComponent();
             ci.topActivity = top.intent.getComponent();
             ci.lastActiveTime = task.lastActiveTime;
+            if (focusedStack && topTask) {
+                // Give the latest time to ensure foreground task can be sorted
+                // at the first, because lastActiveTime of creating task is 0.
+                ci.lastActiveTime = System.currentTimeMillis();
+                topTask = false;
+            }
 
             if (top.task != null) {
                 ci.description = top.task.lastDescription;
             }
             ci.numActivities = numActivities;
             ci.numRunning = numRunning;
-            //System.out.println(
-            //    "#" + maxNum + ": " + " descr=" + ci.description);
             list.add(ci);
         }
     }
 
     public void unhandledBackLocked() {
         final int top = mTaskHistory.size() - 1;
-        if (DEBUG_SWITCH) Slog.d(
-            TAG, "Performing unhandledBack(): top activity at " + top);
+        if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
         if (top >= 0) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities;
             int activityTop = activities.size() - 1;
@@ -4106,7 +4129,7 @@
      */
     boolean handleAppDiedLocked(ProcessRecord app) {
         if (mPausingActivity != null && mPausingActivity.app == app) {
-            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG,
+            if (DEBUG_PAUSE || DEBUG_CLEANUP) Slog.v(TAG_PAUSE,
                     "App died while pausing: " + mPausingActivity);
             mPausingActivity = null;
         }
@@ -4205,14 +4228,22 @@
     }
 
     void removeTask(TaskRecord task, String reason) {
-        removeTask(task, reason, true);
+        removeTask(task, reason, true /* notMoving */);
     }
 
-    void removeTask(TaskRecord task, String reason, boolean removeFromWindowManager) {
-        mStackSupervisor.endLockTaskModeIfTaskEnding(task);
-        if (removeFromWindowManager) {
+    /**
+     * Removes the input task from this stack.
+     * @param task to remove.
+     * @param reason for removal.
+     * @param notMoving task to another stack. In the case we are moving we don't want to perform
+     *                  some operations on the task like removing it from window manager or recents.
+     */
+    void removeTask(TaskRecord task, String reason, boolean notMoving) {
+        if (notMoving) {
+            mStackSupervisor.endLockTaskModeIfTaskEnding(task);
             mWindowManager.removeTask(task.taskId);
         }
+
         final ActivityRecord r = mResumedActivity;
         if (r != null && r.task == task) {
             mResumedActivity = null;
@@ -4229,7 +4260,7 @@
         mTaskHistory.remove(task);
         updateTaskMovement(task, true);
 
-        if (task.mActivities.isEmpty()) {
+        if (notMoving && task.mActivities.isEmpty()) {
             final boolean isVoiceSession = task.voiceSession != null;
             if (isVoiceSession) {
                 try {
@@ -4246,7 +4277,7 @@
         }
 
         if (mTaskHistory.isEmpty()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack=" + this);
+            if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
             final boolean notHomeStack = !isHomeStack();
             if (isOnHomeDisplay()) {
                 String myReason = reason + " leftTaskHistoryEmpty";
@@ -4282,7 +4313,7 @@
     void addTask(final TaskRecord task, final boolean toTop, boolean moving) {
         task.stack = this;
         if (toTop) {
-            insertTaskAtTop(task);
+            insertTaskAtTop(task, null);
         } else {
             mTaskHistory.add(0, task);
             updateTaskMovement(task, false);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index f874244..c2f6bfd 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -23,17 +23,11 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
-import static com.android.server.am.ActivityManagerService.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_RESULTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerService.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
-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.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 static com.android.server.am.ActivityStack.ActivityState.*;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -120,6 +114,13 @@
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
+    private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE;
+    private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_STACK = TAG + POSTFIX_STACK;
+    private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+    private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING;
 
     static final boolean DEBUG = DEBUG_ALL || false;
     static final boolean DEBUG_ADD_REMOVE = DEBUG || false;
@@ -129,7 +130,7 @@
     static final boolean DEBUG_RELEASE = DEBUG || false;
     static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
-    static final boolean DEBUG_STATES = DEBUG || true;
+    static final boolean DEBUG_STATES = DEBUG || false;
     static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
@@ -155,8 +156,7 @@
     static final int LOCK_TASK_START_MSG = FIRST_SUPERVISOR_STACK_MSG + 9;
     static final int LOCK_TASK_END_MSG = FIRST_SUPERVISOR_STACK_MSG + 10;
     static final int CONTAINER_CALLBACK_TASK_LIST_EMPTY = FIRST_SUPERVISOR_STACK_MSG + 11;
-    static final int CONTAINER_TASK_LIST_EMPTY_TIMEOUT = FIRST_SUPERVISOR_STACK_MSG + 12;
-    static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 13;
+    static final int LAUNCH_TASK_BEHIND_COMPLETE = FIRST_SUPERVISOR_STACK_MSG + 12;
 
     private final static String VIRTUAL_DISPLAY_BASE_NAME = "ActivityViewVirtualDisplay";
 
@@ -381,7 +381,7 @@
     }
 
     void notifyActivityDrawnForKeyguard() {
-        if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
+        if (DEBUG_LOCKSCREEN) mService.logLockScreen("");
         mWindowManager.notifyActivityDrawnForKeyguard();
     }
 
@@ -422,7 +422,7 @@
         // The home stack should either be at the top or bottom of the stack list.
         if ((toFront && (stacks.get(topNdx) != mHomeStack))
                 || (!toFront && (stacks.get(0) != mHomeStack))) {
-            if (DEBUG_STACK) Slog.d(TAG, "moveHomeTask: topStack old="
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "moveHomeTask: topStack old="
                     + ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx))
                     + " new=" + mFocusedStack);
             stacks.remove(mHomeStack);
@@ -510,10 +510,10 @@
         }
 
         // Don't give up! Look in recents.
-        if (DEBUG_RECENTS) Slog.v(TAG, "Looking for task id=" + id + " in recents");
+        if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
         TaskRecord task = mRecentTasks.taskForIdLocked(id);
         if (task == null) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "\tDidn't find task id=" + id + " in recents");
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "\tDidn't find task id=" + id + " in recents");
             return null;
         }
 
@@ -522,10 +522,11 @@
         }
 
         if (!restoreRecentTaskLocked(task)) {
-            if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
+            if (DEBUG_RECENTS) Slog.w(TAG_RECENTS,
+                    "Couldn't restore task id=" + id + " found in recents");
             return null;
         }
-        if (DEBUG_RECENTS) Slog.w(TAG, "Restored task id=" + id + " from in recents");
+        if (DEBUG_RECENTS) Slog.w(TAG_RECENTS, "Restored task id=" + id + " from in recents");
         return task;
     }
 
@@ -633,14 +634,14 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (isFrontStack(stack)) {
                     final ActivityRecord r = stack.mResumedActivity;
-                    if (r != null && r.state != ActivityState.RESUMED) {
+                    if (r != null && r.state != RESUMED) {
                         return false;
                     }
                 }
             }
         }
         // TODO: Not sure if this should check if all Paused are complete too.
-        if (DEBUG_STACK) Slog.d(TAG,
+        if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "allResumedActivitiesComplete: mLastFocusedStack changing from=" +
                 mLastFocusedStack + " to=" + mFocusedStack);
         mLastFocusedStack = mFocusedStack;
@@ -648,17 +649,21 @@
     }
 
     boolean allResumedActivitiesVisible() {
+        boolean foundResumed = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.mResumedActivity;
-                if (r != null && (!r.nowVisible || mWaitingVisibleActivities.contains(r))) {
-                    return false;
+                if (r != null) {
+                    if (!r.nowVisible || mWaitingVisibleActivities.contains(r)) {
+                        return false;
+                    }
+                    foundResumed = true;
                 }
             }
         }
-        return true;
+        return foundResumed;
     }
 
     /**
@@ -690,9 +695,7 @@
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.mPausingActivity;
-                if (r != null && r.state != ActivityState.PAUSED
-                        && r.state != ActivityState.STOPPED
-                        && r.state != ActivityState.STOPPING) {
+                if (r != null && r.state != PAUSED && r.state != STOPPED && r.state != STOPPING) {
                     if (DEBUG_STATES) {
                         Slog.d(TAG, "allPausedActivitiesComplete: r=" + r + " state=" + r.state);
                         pausing = false;
@@ -897,7 +900,7 @@
         ActivityContainer container = (ActivityContainer)iContainer;
         synchronized (mService) {
             if (container != null && container.mParentActivity != null &&
-                    container.mParentActivity.state != ActivityState.RESUMED) {
+                    container.mParentActivity.state != RESUMED) {
                 // Cannot start a child activity if the parent is not resumed.
                 return ActivityManager.START_CANCELED;
             }
@@ -1027,7 +1030,7 @@
                     } while (!outResult.timeout && outResult.who == null);
                 } else if (res == ActivityManager.START_TASK_TO_FRONT) {
                     ActivityRecord r = stack.topRunningActivityLocked(null);
-                    if (r.nowVisible && r.state == ActivityState.RESUMED) {
+                    if (r.nowVisible && r.state == RESUMED) {
                         outResult.timeout = false;
                         outResult.who = new ComponentName(r.info.packageName, r.info.name);
                         outResult.totalTime = 0;
@@ -1178,10 +1181,9 @@
                 results = r.results;
                 newIntents = r.newIntents;
             }
-            if (DEBUG_SWITCH) Slog.v(TAG, "Launching: " + r
-                    + " icicle=" + r.icicle
-                    + " with results=" + results + " newIntents=" + newIntents
-                    + " andResume=" + andResume);
+            if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
+                    "Launching: " + r + " icicle=" + r.icicle + " with results=" + results
+                    + " newIntents=" + newIntents + " andResume=" + andResume);
             if (andResume) {
                 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
                         r.userId, System.identityHashCode(r),
@@ -1227,7 +1229,7 @@
                 app.hasShownUi = true;
                 app.pendingUiClean = true;
             }
-            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_TOP);
+            app.forceProcessStateUpTo(mService.mTopProcessState);
             app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                     System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                     new Configuration(stack.mOverrideConfig), r.compat, r.launchedFromPackage,
@@ -1290,7 +1292,7 @@
             // other state.
             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r
                     + " (starting in stopped state)");
-            r.state = ActivityState.STOPPED;
+            r.state = STOPPED;
             r.stopped = true;
         }
 
@@ -1381,8 +1383,8 @@
         ActivityRecord resultRecord = null;
         if (resultTo != null) {
             sourceRecord = isInAnyStackLocked(resultTo);
-            if (DEBUG_RESULTS) Slog.v(
-                TAG, "Will send result to " + resultTo + " " + sourceRecord);
+            if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
+                    "Will send result to " + resultTo + " " + sourceRecord);
             if (sourceRecord != null) {
                 if (requestCode >= 0 && !sourceRecord.finishing) {
                     resultRecord = sourceRecord;
@@ -1726,7 +1728,8 @@
         // 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;
-        if (DEBUG_USER_LEAVING) Slog.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving);
+        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                "startActivity() => mUserLeaving=" + mUserLeaving);
 
         // If the caller has asked not to resume at this point, we make note
         // of this in the record so that we can skip it when trying to find
@@ -1933,7 +1936,7 @@
                         }
                     }
                     if (!movedToFront) {
-                        if (DEBUG_TASKS) Slog.d(TAG, "Bring to front target: " + targetStack
+                        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
                                 + " from " + intentActivity);
                         targetStack.moveToFront("intentActivityFound");
                     }
@@ -2139,8 +2142,8 @@
                         newTaskIntent != null ? newTaskIntent : intent,
                         voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                         taskToAffiliate);
-                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r + " in new task " +
-                        r.task);
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                        "Starting new activity " + r + " in new task " + r.task);
             } else {
                 r.setTask(reuseTask, taskToAffiliate);
             }
@@ -2207,7 +2210,7 @@
             // to keep the new one in the same task as the one that is starting
             // it.
             r.setTask(sourceTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
                     + " in existing task " + r.task + " from source " + sourceRecord);
 
         } else if (inTask != null) {
@@ -2246,7 +2249,7 @@
             }
 
             r.setTask(inTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
                     + " in explicit task " + r.task);
 
         } else {
@@ -2259,7 +2262,7 @@
             r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
                             r.info, intent, null, null, true), null);
             mWindowManager.moveTaskToTop(r.task.taskId);
-            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
                     + " in new guessed " + r.task);
         }
 
@@ -2599,8 +2602,8 @@
             return;
         }
         task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options, reason);
-        if (DEBUG_STACK) Slog.d(TAG, "findTaskToMoveToFront: moved to front of stack="
-                + task.stack);
+        if (DEBUG_STACK) Slog.d(TAG_STACK,
+                "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
 
     ActivityStack getStack(int stackId) {
@@ -2793,20 +2796,20 @@
             stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
             // Restore home stack to top.
             moveHomeStack(true, "restoreRecentTask");
-            if (DEBUG_RECENTS)
-                Slog.v(TAG, "Created stack=" + stack + " for recents restoration.");
+            if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+                    "Created stack=" + stack + " for recents restoration.");
         }
 
         if (stack == null) {
             // What does this mean??? Not sure how we would get here...
-            if (DEBUG_RECENTS)
-                Slog.v(TAG, "Unable to find/create stack to restore recent task=" + task);
+            if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+                    "Unable to find/create stack to restore recent task=" + task);
             return false;
         }
 
         stack.addTask(task, false, false);
-        if (DEBUG_RECENTS)
-            Slog.v(TAG, "Added restored task=" + task + " to stack=" + stack);
+        if (DEBUG_RECENTS) Slog.v(TAG_RECENTS,
+                "Added restored task=" + task + " to stack=" + stack);
         final ArrayList<ActivityRecord> activities = task.mActivities;
         for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
             final ActivityRecord r = activities.get(activityNdx);
@@ -2832,25 +2835,25 @@
         }
         mWindowManager.moveTaskToStack(taskId, stackId, toTop);
         if (task.stack != null) {
-            task.stack.removeTask(task, "moveTaskToStack", false);
+            task.stack.removeTask(task, "moveTaskToStack", false /* notMoving */);
         }
         stack.addTask(task, toTop, true);
         resumeTopActivitiesLocked();
     }
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
-        if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + r);
+        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             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: (home activity) " + stack);
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (home activity) " + stack);
                     continue;
                 }
                 if (!stack.mActivityContainer.isEligibleForNewTasks()) {
-                    if (DEBUG_TASKS) Slog.d(TAG, "Skipping stack: (new task not allowed) " +
-                            stack);
+                    if (DEBUG_TASKS) Slog.d(TAG_TASKS,
+                            "Skipping stack: (new task not allowed) " + stack);
                     continue;
                 }
                 final ActivityRecord ar = stack.findTaskLocked(r);
@@ -2859,7 +2862,7 @@
                 }
             }
         }
-        if (DEBUG_TASKS) Slog.d(TAG, "No task found");
+        if (DEBUG_TASKS) Slog.d(TAG_TASKS, "No task found");
         return null;
     }
 
@@ -2968,7 +2971,7 @@
 
             if (mStoppingActivities.size() > 0) {
                 // Still need to tell some activities to stop; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to stop "
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to stop "
                         + mStoppingActivities.size() + " activities");
                 scheduleIdleLocked();
                 dontSleep = true;
@@ -2976,7 +2979,7 @@
 
             if (mGoingToSleepActivities.size() > 0) {
                 // Still need to tell some activities to sleep; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still need to sleep "
+                if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Sleep still need to sleep "
                         + mGoingToSleepActivities.size() + " activities");
                 dontSleep = true;
             }
@@ -3127,16 +3130,14 @@
             // First, if we find an activity that is in the process of being destroyed,
             // then we just aren't going to do anything for now; we want things to settle
             // down before we try to prune more activities.
-            if (r.finishing || r.state == ActivityState.DESTROYING
-                    || r.state == ActivityState.DESTROYED) {
+            if (r.finishing || r.state == DESTROYING || r.state == DESTROYED) {
                 if (DEBUG_RELEASE) Slog.d(TAG, "Abort release; already destroying: " + r);
                 return;
             }
             // Don't consider any activies that are currently not in a state where they
             // can be destroyed.
-            if (r.visible || !r.stopped || !r.haveState
-                    || r.state == ActivityState.RESUMED || r.state == ActivityState.PAUSING
-                    || r.state == ActivityState.PAUSED || r.state == ActivityState.STOPPING) {
+            if (r.visible || !r.stopped || !r.haveState || r.state == RESUMED || r.state == PAUSING
+                    || r.state == PAUSED || r.state == STOPPING) {
                 if (DEBUG_RELEASE) Slog.d(TAG, "Not releasing in-use activity: " + r);
                 continue;
             }
@@ -3254,39 +3255,34 @@
     }
 
     void validateTopActivitiesLocked() {
-        // FIXME
-/*        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ActivityStack stack = stacks.get(stackNdx);
-            final ActivityRecord r = stack.topRunningActivityLocked(null);
-            final ActivityState state = r == null ? ActivityState.DESTROYED : r.state;
-            if (isFrontStack(stack)) {
-                if (r == null) {
-                    Slog.e(TAG, "validateTop...: null top activity, stack=" + stack);
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                final ActivityStack stack = stacks.get(stackNdx);
+                final ActivityRecord r = stack.topRunningActivityLocked(null);
+                final ActivityState state = r == null ? DESTROYED : r.state;
+                if (isFrontStack(stack)) {
+                    if (r == null) Slog.e(TAG,
+                            "validateTop...: null top activity, stack=" + stack);
+                    else {
+                        final ActivityRecord pausing = stack.mPausingActivity;
+                        if (pausing != null && pausing == r) Slog.e(TAG,
+                                "validateTop...: top stack has pausing activity r=" + r
+                                + " state=" + state);
+                        if (state != INITIALIZING && state != RESUMED) Slog.e(TAG,
+                                "validateTop...: activity in front not resumed r=" + r
+                                + " state=" + state);
+                    }
                 } else {
-                    final ActivityRecord pausing = stack.mPausingActivity;
-                    if (pausing != null && pausing == r) {
-                        Slog.e(TAG, "validateTop...: top stack has pausing activity r=" + r +
-                            " state=" + state);
-                    }
-                    if (state != ActivityState.INITIALIZING && state != ActivityState.RESUMED) {
-                        Slog.e(TAG, "validateTop...: activity in front not resumed r=" + r +
-                                " state=" + state);
-                    }
-                }
-            } else {
-                final ActivityRecord resumed = stack.mResumedActivity;
-                if (resumed != null && resumed == r) {
-                    Slog.e(TAG, "validateTop...: back stack has resumed activity r=" + r +
-                        " state=" + state);
-                }
-                if (r != null && (state == ActivityState.INITIALIZING
-                        || state == ActivityState.RESUMED)) {
-                    Slog.e(TAG, "validateTop...: activity in back resumed r=" + r +
-                            " state=" + state);
+                    final ActivityRecord resumed = stack.mResumedActivity;
+                    if (resumed != null && resumed == r) Slog.e(TAG,
+                            "validateTop...: back stack has resumed activity r=" + r
+                            + " state=" + state);
+                    if (r != null && (state == INITIALIZING || state == RESUMED)) Slog.e(TAG,
+                            "validateTop...: activity in back resumed r=" + r + " state=" + state);
                 }
             }
         }
-*/
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -3512,7 +3508,7 @@
         mHandler.sendMessage(mHandler.obtainMessage(HANDLE_DISPLAY_CHANGED, displayId, 0));
     }
 
-    public void handleDisplayAddedLocked(int displayId) {
+    private void handleDisplayAdded(int displayId) {
         boolean newDisplay;
         synchronized (mService) {
             newDisplay = mActivityDisplays.get(displayId) == null;
@@ -3530,7 +3526,7 @@
         }
     }
 
-    public void handleDisplayRemovedLocked(int displayId) {
+    private void handleDisplayRemoved(int displayId) {
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
             if (activityDisplay != null) {
@@ -3544,7 +3540,7 @@
         mWindowManager.onDisplayRemoved(displayId);
     }
 
-    public void handleDisplayChangedLocked(int displayId) {
+    private void handleDisplayChanged(int displayId) {
         synchronized (mService) {
             ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
             if (activityDisplay != null) {
@@ -3554,7 +3550,7 @@
         mWindowManager.onDisplayChanged(displayId);
     }
 
-    StackInfo getStackInfo(ActivityStack stack) {
+    private StackInfo getStackInfoLocked(ActivityStack stack) {
         StackInfo info = new StackInfo();
         mWindowManager.getStackBounds(stack.mStackId, info.bounds);
         info.displayId = Display.DEFAULT_DISPLAY;
@@ -3580,7 +3576,7 @@
     StackInfo getStackInfoLocked(int stackId) {
         ActivityStack stack = getStack(stackId);
         if (stack != null) {
-            return getStackInfo(stack);
+            return getStackInfoLocked(stack);
         }
         return null;
     }
@@ -3590,7 +3586,7 @@
         for (int displayNdx = 0; displayNdx < mActivityDisplays.size(); ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int ndx = stacks.size() - 1; ndx >= 0; --ndx) {
-                list.add(getStackInfo(stacks.get(ndx)));
+                list.add(getStackInfoLocked(stacks.get(ndx)));
             }
         }
         return list;
@@ -3710,13 +3706,13 @@
                     }
                 } break;
                 case HANDLE_DISPLAY_ADDED: {
-                    handleDisplayAddedLocked(msg.arg1);
+                    handleDisplayAdded(msg.arg1);
                 } break;
                 case HANDLE_DISPLAY_CHANGED: {
-                    handleDisplayChangedLocked(msg.arg1);
+                    handleDisplayChanged(msg.arg1);
                 } break;
                 case HANDLE_DISPLAY_REMOVED: {
-                    handleDisplayRemovedLocked(msg.arg1);
+                    handleDisplayRemoved(msg.arg1);
                 } break;
                 case CONTAINER_CALLBACK_VISIBILITY: {
                     final ActivityContainer container = (ActivityContainer) msg.obj;
@@ -3806,15 +3802,6 @@
                         }
                     }
                 } break;
-                case CONTAINER_TASK_LIST_EMPTY_TIMEOUT: {
-                    synchronized (mService) {
-                        Slog.w(TAG, "Timeout waiting for all activities in task to finish. " +
-                                msg.obj);
-                        final ActivityContainer container = (ActivityContainer) msg.obj;
-                        container.mStack.finishAllActivitiesLocked(true);
-                        container.onTaskListEmptyLocked();
-                    }
-                } break;
                 case LAUNCH_TASK_BEHIND_COMPLETE: {
                     synchronized (mService) {
                         ActivityRecord r = ActivityRecord.forTokenLocked((IBinder) msg.obj);
@@ -3851,12 +3838,12 @@
                 mStackId = stackId;
                 mStack = new ActivityStack(this, mRecentTasks);
                 mIdString = "ActivtyContainer{" + mStackId + "}";
-                if (DEBUG_STACK) Slog.d(TAG, "Creating " + this);
+                if (DEBUG_STACK) Slog.d(TAG_STACK, "Creating " + this);
             }
         }
 
         void attachToDisplayLocked(ActivityDisplay activityDisplay) {
-            if (DEBUG_STACK) Slog.d(TAG, "attachToDisplayLocked: " + this
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "attachToDisplayLocked: " + this
                     + " to display=" + activityDisplay);
             mActivityDisplay = activityDisplay;
             mStack.mDisplayId = activityDisplay.mDisplayId;
@@ -3919,10 +3906,6 @@
                 }
                 mContainerState = CONTAINER_STATE_FINISHING;
 
-                final Message msg =
-                        mHandler.obtainMessage(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-                mHandler.sendMessageDelayed(msg, 2000);
-
                 long origId = Binder.clearCallingIdentity();
                 try {
                     mStack.finishAllActivitiesLocked(false);
@@ -3934,7 +3917,7 @@
         }
 
         protected void detachLocked() {
-            if (DEBUG_STACK) Slog.d(TAG, "detachLocked: " + this + " from display="
+            if (DEBUG_STACK) Slog.d(TAG_STACK, "detachLocked: " + this + " from display="
                     + mActivityDisplay + " Callers=" + Debug.getCallers(2));
             if (mActivityDisplay != null) {
                 mActivityDisplay.detachActivitiesLocked(mStack);
@@ -4042,7 +4025,6 @@
         }
 
         void onTaskListEmptyLocked() {
-            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
             detachLocked();
             deleteActivityContainer(this);
             mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
@@ -4111,8 +4093,8 @@
 
             setSurfaceIfReadyLocked();
 
-            if (DEBUG_STACK) Slog.d(TAG, "setSurface: " + this + " to display="
-                    + virtualActivityDisplay);
+            if (DEBUG_STACK) Slog.d(TAG_STACK,
+                    "setSurface: " + this + " to display=" + virtualActivityDisplay);
         }
 
         @Override
@@ -4135,7 +4117,7 @@
         }
 
         private void setSurfaceIfReadyLocked() {
-            if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
+            if (DEBUG_STACK) Slog.v(TAG_STACK, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
             if (mDrawn && mSurface != null && mContainerState == CONTAINER_STATE_NO_SURFACE) {
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(mSurface);
@@ -4178,13 +4160,13 @@
         }
 
         void attachActivities(ActivityStack stack) {
-            if (DEBUG_STACK) Slog.v(TAG, "attachActivities: attaching " + stack + " to displayId="
-                    + mDisplayId);
+            if (DEBUG_STACK) Slog.v(TAG_STACK,
+                    "attachActivities: attaching " + stack + " to displayId=" + mDisplayId);
             mStacks.add(stack);
         }
 
         void detachActivitiesLocked(ActivityStack stack) {
-            if (DEBUG_STACK) Slog.v(TAG, "detachActivitiesLocked: detaching " + stack
+            if (DEBUG_STACK) Slog.v(TAG_STACK, "detachActivitiesLocked: detaching " + stack
                     + " from displayId=" + mDisplayId);
             mStacks.remove(stack);
         }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index c8db3be..ed108c2 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -40,6 +40,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.telephony.DataConnectionRealTimeInfo;
 import android.telephony.SignalStrength;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
@@ -122,6 +123,7 @@
         mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_radioScanningTimeout)
                 * 1000L);
+        mStats.setPowerProfile(new PowerProfile(context));
     }
 
     /**
@@ -258,6 +260,12 @@
         }
     }
 
+    public boolean isCharging() {
+        synchronized (mStats) {
+            return mStats.isCharging();
+        }
+    }
+
     public long computeBatteryTimeRemaining() {
         synchronized (mStats) {
             long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
@@ -541,6 +549,15 @@
         }
     }
 
+    @Override
+    public void noteWifiRadioPowerState(int powerState, long tsNanos) {
+        enforceCallingPermission();
+
+        // There was a change in WiFi power state.
+        // Collect data now for the past activity.
+        mHandler.scheduleSync();
+    }
+
     public void noteWifiRunning(WorkSource ws) {
         enforceCallingPermission();
         synchronized (mStats) {
@@ -1095,13 +1112,29 @@
                 result.mTimestamp = info.getTimeStamp();
                 result.mStackState = info.getStackState();
                 result.mControllerTxTimeMs =
-                        info.getControllerTxTimeMillis()- mLastInfo.mControllerTxTimeMs;
+                        info.mControllerTxTimeMs - mLastInfo.mControllerTxTimeMs;
                 result.mControllerRxTimeMs =
-                        info.getControllerRxTimeMillis() - mLastInfo.mControllerRxTimeMs;
-                result.mControllerIdleTimeMs =
-                        info.getControllerIdleTimeMillis() - mLastInfo.mControllerIdleTimeMs;
+                        info.mControllerRxTimeMs - mLastInfo.mControllerRxTimeMs;
                 result.mControllerEnergyUsed =
-                        info.getControllerEnergyUsed() - mLastInfo.mControllerEnergyUsed;
+                        info.mControllerEnergyUsed - mLastInfo.mControllerEnergyUsed;
+
+                // WiFi calculates the idle time as a difference from the on time and the various
+                // Rx + Tx times. There seems to be some missing time there because this sometimes
+                // becomes negative. Just cap it at 0 and move on.
+                result.mControllerIdleTimeMs =
+                        Math.max(0, info.mControllerIdleTimeMs - mLastInfo.mControllerIdleTimeMs);
+
+                if (result.mControllerTxTimeMs < 0 ||
+                        result.mControllerRxTimeMs < 0) {
+                    // The stats were reset by the WiFi system (which is why our delta is negative).
+                    // Returns the unaltered stats.
+                    result.mControllerEnergyUsed = info.mControllerEnergyUsed;
+                    result.mControllerRxTimeMs = info.mControllerRxTimeMs;
+                    result.mControllerTxTimeMs = info.mControllerTxTimeMs;
+                    result.mControllerIdleTimeMs = info.mControllerIdleTimeMs;
+
+                    Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result);
+                }
                 mLastInfo = info;
                 return result;
             }
@@ -1133,6 +1166,12 @@
      */
     void updateExternalStats() {
         synchronized (mExternalStatsLock) {
+            if (mContext == null) {
+                // We haven't started yet (which means the BatteryStatsImpl object has
+                // no power profile. Don't consume data we can't compute yet.
+                return;
+            }
+
             final WifiActivityEnergyInfo wifiEnergyInfo = pullWifiEnergyInfoLocked();
             final BluetoothActivityEnergyInfo bluetoothEnergyInfo = pullBluetoothEnergyInfoLocked();
             synchronized (mStats) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 34c1c53..5b5ebef 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -50,7 +50,7 @@
  * foreground priority, and one for normal (background-priority) broadcasts.
  */
 public final class BroadcastQueue {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "BroadcastQueue" : TAG_AM;
+    private static final String TAG = "BroadcastQueue";
     private static final String TAG_MU = TAG + POSTFIX_MU;
     private static final String TAG_BROADCAST = TAG + POSTFIX_BROADCAST;
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 9c0db87..531de46 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -222,19 +222,26 @@
                     owner.cancelIntentSenderLocked(this, true);
                     canceled = true;
                 }
+
                 Intent finalIntent = key.requestIntent != null
                         ? new Intent(key.requestIntent) : new Intent();
-                if (intent != null) {
-                    int changes = finalIntent.fillIn(intent, key.flags);
-                    if ((changes&Intent.FILL_IN_DATA) == 0) {
+
+                final boolean immutable = (key.flags & PendingIntent.FLAG_IMMUTABLE) != 0;
+                if (!immutable) {
+                    if (intent != null) {
+                        int changes = finalIntent.fillIn(intent, key.flags);
+                        if ((changes & Intent.FILL_IN_DATA) == 0) {
+                            resolvedType = key.requestResolvedType;
+                        }
+                    } else {
                         resolvedType = key.requestResolvedType;
                     }
+                    flagsMask &= ~Intent.IMMUTABLE_FLAGS;
+                    flagsValues &= flagsMask;
+                    finalIntent.setFlags((finalIntent.getFlags() & ~flagsMask) | flagsValues);
                 } else {
                     resolvedType = key.requestResolvedType;
                 }
-                flagsMask &= ~Intent.IMMUTABLE_FLAGS;
-                flagsValues &= flagsMask;
-                finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues);
 
                 final long origId = Binder.clearCallingIdentity();
 
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index c7aa94c..cdfcd0c 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -368,6 +368,12 @@
             case ActivityManager.PROCESS_STATE_TOP:
                 procState = "T ";
                 break;
+            case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
+                procState = "FS";
+                break;
+            case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
+                procState = "TS";
+                break;
             case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
                 procState = "IF";
                 break;
@@ -475,6 +481,8 @@
         PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT
         PROC_MEM_PERSISTENT,            // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BACKUP
@@ -492,6 +500,8 @@
         PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_FIRST_TOP_INTERVAL,         // ActivityManager.PROCESS_STATE_TOP
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_BACKUP
@@ -509,6 +519,8 @@
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_SHORT_INTERVAL,             // ActivityManager.PROCESS_STATE_TOP
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BACKUP
@@ -526,6 +538,8 @@
         PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_TEST_FIRST_TOP_INTERVAL,        // ActivityManager.PROCESS_STATE_TOP
+        PSS_FIRST_BACKGROUND_INTERVAL,      // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_FIRST_BACKGROUND_INTERVAL,      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
@@ -543,6 +557,8 @@
         PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT
         PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TOP
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_BACKUP
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 7c921ac..29e14f8 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -426,7 +426,7 @@
                         tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList);
                 origBase.makeInactive();
             }
-            baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid,
+            baseProcessTracker = tracker.getProcessStateLocked(info.packageName, uid,
                     info.versionCode, processName);
             baseProcessTracker.makeActive();
             for (int i=0; i<pkgList.size(); i++) {
@@ -434,7 +434,7 @@
                 if (holder.state != null && holder.state != origBase) {
                     holder.state.makeInactive();
                 }
-                holder.state = tracker.getProcessStateLocked(pkgList.keyAt(i), info.uid,
+                holder.state = tracker.getProcessStateLocked(pkgList.keyAt(i), uid,
                         info.versionCode, processName);
                 if (holder.state != baseProcessTracker) {
                     holder.state.makeActive();
@@ -624,7 +624,7 @@
                     versionCode);
             if (baseProcessTracker != null) {
                 holder.state = tracker.getProcessStateLocked(
-                        pkg, info.uid, versionCode, processName);
+                        pkg, uid, versionCode, processName);
                 pkgList.put(pkg, holder);
                 if (holder.state != baseProcessTracker) {
                     holder.state.makeActive();
@@ -671,7 +671,7 @@
                 }
                 pkgList.clear();
                 ProcessStats.ProcessState ps = tracker.getProcessStateLocked(
-                        info.packageName, info.uid, info.versionCode, processName);
+                        info.packageName, uid, info.versionCode, processName);
                 ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
                         info.versionCode);
                 holder.state = ps;
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index 04912d0..3a20ded 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -16,10 +16,7 @@
 
 package com.android.server.am;
 
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerService.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
 
 import android.app.ActivityManager;
@@ -44,6 +41,8 @@
  */
 class RecentTasks extends ArrayList<TaskRecord> {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "RecentTasks" : TAG_AM;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
 
     // Maximum number recent bitmaps to keep in memory.
     private static final int MAX_RECENT_BITMAPS = 3;
@@ -83,8 +82,8 @@
         for (int i = size() - 1; i >= 0; --i) {
             TaskRecord tr = get(i);
             if (tr.userId == userId) {
-                if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
-                        + " when finishing user" + userId);
+                if(DEBUG_TASKS) Slog.i(TAG_TASKS,
+                        "remove RecentTask " + tr + " when finishing user" + userId);
                 remove(i);
                 tr.removedFromRecents();
             }
@@ -170,21 +169,21 @@
                             continue;
                         } else {
                             // Otherwise just not available for now.
-                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
                                     "Making recent unavailable: " + task);
                             task.isAvailable = false;
                         }
                     } else {
                         if (!ai.enabled || !ai.applicationInfo.enabled
                                 || (ai.applicationInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG,
+                            if (DEBUG_RECENTS && task.isAvailable) Slog.d(TAG_RECENTS,
                                     "Making recent unavailable: " + task
                                     + " (enabled=" + ai.enabled + "/" + ai.applicationInfo.enabled
                                     + " flags=" + Integer.toHexString(ai.applicationInfo.flags)
                                     + ")");
                             task.isAvailable = false;
                         } else {
-                            if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG,
+                            if (DEBUG_RECENTS && !task.isAvailable) Slog.d(TAG_RECENTS,
                                     "Making recent available: " + task);
                             task.isAvailable = true;
                         }
@@ -210,7 +209,7 @@
             top = top.mNextAffiliate;
             topIndex--;
         }
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding affilliates starting at "
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding affilliates starting at "
                 + topIndex + " from intial " + taskIndex);
         // Find the end of the chain, doing a sanity check along the way.
         boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
@@ -218,7 +217,7 @@
         TaskRecord prev = top;
         while (endIndex < recentsCount) {
             TaskRecord cur = get(endIndex);
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: looking at next chain @"
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
                     + endIndex + " " + cur);
             if (cur == top) {
                 // Verify start of the chain.
@@ -249,7 +248,7 @@
                             + cur.mPrevAffiliate);
                     sane = false;
                 }
-                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: end of chain @" + endIndex);
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: end of chain @" + endIndex);
                 break;
             } else {
                 // Verify middle of the chain's prev points to a valid item.
@@ -290,12 +289,12 @@
             // All looks good, we can just move all of the affiliated tasks
             // to the top.
             for (int i=topIndex; i<=endIndex; i++) {
-                if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving affiliated " + task
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
                         + " from " + i + " to " + (i-topIndex));
                 TaskRecord cur = remove(i);
                 add(i - topIndex, cur);
             }
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: done moving tasks  " +  topIndex
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " +  topIndex
                     + " to " + endIndex);
             return true;
         }
@@ -312,19 +311,20 @@
         int recentsCount = size();
         // Quick case: never add voice sessions.
         if (task.voiceSession != null) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: not adding voice interaction " + task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                    "addRecent: not adding voice interaction " + task);
             return;
         }
         // Another quick case: check if the top-most recent task is the same.
         if (!isAffiliated && recentsCount > 0 && get(0) == task) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: already at top: " + task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: already at top: " + task);
             return;
         }
         // Another quick case: check if this is part of a set of affiliated
         // tasks that are at the top.
         if (isAffiliated && recentsCount > 0 && task.inRecents
                 && task.mAffiliatedTaskId == get(0).mAffiliatedTaskId) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: affiliated " + get(0)
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: affiliated " + get(0)
                     + " at top when adding " + task);
             return;
         }
@@ -341,7 +341,7 @@
                     remove(taskIndex);
                     add(0, task);
                     mService.notifyTaskPersisterLocked(task, false);
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: moving to top " + task
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving to top " + task
                             + " from " + taskIndex);
                     return;
                 } else {
@@ -361,7 +361,7 @@
             }
         }
 
-        if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: trimming tasks for " + task);
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: trimming tasks for " + task);
         trimForTaskLocked(task, true);
 
         recentsCount = size();
@@ -376,7 +376,7 @@
             // If this is a simple non-affiliated task, or we had some failure trying to
             // handle it as part of an affilated task, then just place it at the top.
             add(0, task);
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: adding " + task);
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: adding " + task);
         } else if (isAffiliated) {
             // If this is a new affiliated task, then move all of the affiliated tasks
             // to the front and insert this new one.
@@ -398,8 +398,8 @@
                         // after us in the list, so add at their position.
                         taskIndex = otherIndex;
                     }
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: new affiliated task added at "
-                            + taskIndex + ": " + task);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "addRecent: new affiliated task added at " + taskIndex + ": " + task);
                     add(taskIndex, task);
 
                     // Now move everything to the front.
@@ -412,19 +412,19 @@
                     // everything and then go through our general path of adding a new task.
                     needAffiliationFix = true;
                 } else {
-                    if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: couldn't find other affiliation "
-                            + other);
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
+                            "addRecent: couldn't find other affiliation " + other);
                     needAffiliationFix = true;
                 }
             } else {
-                if (DEBUG_RECENTS) Slog.d(TAG,
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                         "addRecent: adding affiliated task without next/prev:" + task);
                 needAffiliationFix = true;
             }
         }
 
         if (needAffiliationFix) {
-            if (DEBUG_RECENTS) Slog.d(TAG, "addRecent: regrouping affiliations");
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: regrouping affiliations");
             cleanupLocked(task.userId);
         }
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 3b34541..82e6d47 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -18,8 +18,7 @@
 
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerDebugConfig.*;
 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;
@@ -58,6 +57,8 @@
 
 final class TaskRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
 
     static final String ATTR_TASKID = "task_id";
     private static final String TAG_INTENT = "intent";
@@ -312,8 +313,7 @@
                     _intent.setSourceBounds(null);
                 }
             }
-            if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
-                    "Setting Intent of " + this + " to " + _intent);
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
             intent = _intent;
             realActivity = _intent != null ? _intent.getComponent() : null;
             origActivity = null;
@@ -325,7 +325,7 @@
                 targetIntent.setComponent(targetComponent);
                 targetIntent.setSelector(null);
                 targetIntent.setSourceBounds(null);
-                if (ActivityManagerService.DEBUG_TASKS) Slog.v(TAG,
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                         "Setting Intent of " + this + " to target " + targetIntent);
                 intent = targetIntent;
                 realActivity = targetComponent;
@@ -821,7 +821,7 @@
     }
 
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
-        if (ActivityManagerService.DEBUG_RECENTS) Slog.i(TAG, "Saving task=" + this);
+        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
 
         out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
         if (realActivity != null) {
@@ -1048,7 +1048,7 @@
             activities.get(activityNdx).task = task;
         }
 
-        if (ActivityManagerService.DEBUG_RECENTS) Slog.d(TAG, "Restored task=" + task);
+        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
         return task;
     }
 
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index f05e6aa..4ccb5ad 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -63,8 +63,10 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.Iterator;
 import java.util.Stack;
+import java.text.DateFormat;
 
 /**
  * @hide
@@ -124,6 +126,8 @@
     }
 
     protected void dump(PrintWriter pw) {
+        pw.println("\nMediaFocusControl dump time: "
+                + DateFormat.getTimeInstance().format(new Date()));
         dumpFocusStack(pw);
         dumpRCStack(pw);
         dumpRCCStack(pw);
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
new file mode 100644
index 0000000..f9b17ed
--- /dev/null
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.camera;
+
+import android.content.Context;
+import android.hardware.ICameraService;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import com.android.server.SystemService;
+
+/**
+ * CameraService is the system_server analog to the camera service running in mediaserver.
+ *
+ * @hide
+ */
+public class CameraService extends SystemService {
+
+    /**
+     * This must match the ICameraService.aidl definition
+     */
+    private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
+
+    // Event arguments to use with the camera service notifySystemEvent call:
+    public static final int NO_EVENT = 0; // NOOP
+    public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
+
+    public CameraService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {}
+
+    @Override
+    public void onSwitchUser(int userHandle) {
+        super.onSwitchUser(userHandle);
+
+        /**
+         * Forward the user switch event to the native camera service running in mediaserver.
+         */
+        IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
+        if (cameraServiceBinder == null) {
+            return; // Camera service not active, there is no need to evict user clients.
+        }
+        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
+        try {
+            cameraServiceRaw.notifySystemEvent(USER_SWITCHED, userHandle);
+        } catch (RemoteException e) {
+            // Do nothing, if camera service is dead, there is no need to evict user clients.
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 191df2f..7866ddc 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -176,6 +176,7 @@
     volatile private PowerManager.WakeLock mSyncManagerWakeLock;
     volatile private boolean mDataConnectionIsConnected = false;
     volatile private boolean mStorageIsLow = false;
+    volatile private boolean mDeviceIsIdle = false;
 
     private final NotificationManager mNotificationMgr;
     private AlarmManager mAlarmService = null;
@@ -221,6 +222,20 @@
                 }
             };
 
+    private BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
+        @Override public void onReceive(Context context, Intent intent) {
+            boolean idle = mPowerManager.isDeviceIdleMode();
+            mDeviceIsIdle = idle;
+            if (idle) {
+                cancelActiveSync(
+                        SyncStorageEngine.EndPoint.USER_ALL_PROVIDER_ALL_ACCOUNTS_ALL,
+                        null /* any sync */);
+            } else {
+                sendCheckAlarmsMessage();
+            }
+        }
+    };
+
     private BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -425,6 +440,9 @@
         intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
         context.registerReceiver(mStorageIntentReceiver, intentFilter);
 
+        intentFilter = new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+        context.registerReceiver(mDeviceIdleReceiver, intentFilter);
+
         intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
         intentFilter.setPriority(100);
         context.registerReceiver(mShutdownIntentReceiver, intentFilter);
@@ -1312,6 +1330,7 @@
             pw.println();
         }
         pw.print("memory low: "); pw.println(mStorageIsLow);
+        pw.print("device idle: "); pw.println(mDeviceIsIdle);
 
         final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
 
@@ -2358,6 +2377,13 @@
                 return Long.MAX_VALUE;
             }
 
+            if (mDeviceIsIdle) {
+                if (isLoggable) {
+                    Log.v(TAG, "maybeStartNextSync: device idle, skipping");
+                }
+                return Long.MAX_VALUE;
+            }
+
             // If the accounts aren't known yet then we aren't ready to run. We will be kicked
             // when the account lookup request does complete.
             if (mRunningAccounts == INITIAL_ACCOUNTS_ARRAY) {
@@ -2984,6 +3010,7 @@
             // method to be called again
             if (!mDataConnectionIsConnected) return;
             if (mStorageIsLow) return;
+            if (mDeviceIsIdle) return;
 
             // When the status bar notification should be raised
             final long notificationTime =
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index c97bdb6..a3c9738 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -348,6 +348,10 @@
         private int mActualBacklight = INITIAL_BACKLIGHT;
         private boolean mChangeInProgress;
 
+        public PhotonicModulator() {
+            super("PhotonicModulator");
+        }
+
         public boolean setState(int state, int backlight) {
             synchronized (mLock) {
                 if (state != mPendingState || backlight != mPendingBacklight) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index ab56b34..fd75077 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -23,16 +23,16 @@
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.os.RemoteException;
-import android.service.fingerprint.FingerprintManager;
 import android.util.ArrayMap;
 import android.util.Slog;
 
 import com.android.server.SystemService;
 
-import android.service.fingerprint.FingerprintUtils;
-import android.service.fingerprint.Fingerprint;
-import android.service.fingerprint.IFingerprintService;
-import android.service.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.FingerprintUtils;
+import android.hardware.fingerprint.Fingerprint;
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.IFingerprintService;
+import android.hardware.fingerprint.IFingerprintServiceReceiver;
 
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.USE_FINGERPRINT;
@@ -363,7 +363,7 @@
             startEnroll(token, groupId, flags);
         }
 
-        @Override 
+        @Override
         // Binder call
         public void authenticate(IBinder token, long sessionId, int groupId, int flags) {
             checkPermission(USE_FINGERPRINT);
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index 7f48768..01547c1 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -68,8 +68,12 @@
         }
 
         if (!tv.isProhibitMode()) {
+            ActiveSource old = ActiveSource.of(tv.getActiveSource());
             tv.updateActiveSource(newActive);
             boolean notifyInputChange = (mCallback == null);
+            if (!old.equals(newActive)) {
+                tv.setPrevPortId(tv.getActivePortId());
+            }
             tv.updateActiveInput(newActive.physicalAddress, notifyInputChange);
             invokeCallback(HdmiControlManager.RESULT_SUCCESS);
         } else {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index d17e9b3..b24bc65 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -71,6 +71,9 @@
             logicalAddress = logical;
             physicalAddress = physical;
         }
+        public static ActiveSource of(ActiveSource source) {
+            return new ActiveSource(source.logicalAddress, source.physicalAddress);
+        }
         public static ActiveSource of(int logical, int physical) {
             return new ActiveSource(logical, physical);
         }
@@ -102,10 +105,10 @@
             StringBuffer s = new StringBuffer();
             String logicalAddressString = (logicalAddress == Constants.ADDR_INVALID)
                     ? "invalid" : String.format("0x%02x", logicalAddress);
-            s.append("logical_address: ").append(logicalAddressString);
+            s.append("(").append(logicalAddressString);
             String physicalAddressString = (physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS)
                     ? "invalid" : String.format("0x%04x", physicalAddress);
-            s.append(", physical_address: ").append(physicalAddressString);
+            s.append(", ").append(physicalAddressString).append(")");
             return s.toString();
         }
     }
@@ -636,7 +639,7 @@
     void addAndStartAction(final HdmiCecFeatureAction action) {
         assertRunOnServiceThread();
         mActions.add(action);
-        if (mService.isPowerStandbyOrTransient()) {
+        if (mService.isPowerStandby()) {
             Slog.i(TAG, "Not ready to start action. Queued for deferred start:" + action);
             return;
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index d5cb5e3..4ac2b48 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -45,6 +45,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.IndentingPrintWriter;
@@ -71,9 +72,8 @@
     @ServiceThreadOnly
     private boolean mArcEstablished = false;
 
-    // Whether ARC feature is enabled or not. The default value is true.
-    // TODO: once adding system setting for it, read the value to it.
-    private boolean mArcFeatureEnabled = true;
+    // Stores whether ARC feature is enabled per port. True by default for all the ARC-enabled ports.
+    private final SparseBooleanArray mArcFeatureEnabled = new SparseBooleanArray();
 
     // Whether System audio mode is activated or not.
     // This becomes true only when all system audio sequences are finished.
@@ -190,6 +190,10 @@
     @ServiceThreadOnly
     protected void onAddressAllocated(int logicalAddress, int reason) {
         assertRunOnServiceThread();
+        List<HdmiPortInfo> ports = mService.getPortInfo();
+        for (HdmiPortInfo port : ports) {
+            mArcFeatureEnabled.put(port.getId(), port.isArcSupported());
+        }
         mService.registerTvInputCallback(mTvInputCallback);
         mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, mService.getPhysicalAddress(), mDeviceType));
@@ -343,7 +347,6 @@
     void updateActiveInput(int path, boolean notifyInputChange) {
         assertRunOnServiceThread();
         // Seq #15
-        setPrevPortId(getActivePortId());
         setActivePath(path);
         // TODO: Handle PAP/PIP case.
         // Show OSD port change banner
@@ -782,6 +785,8 @@
                         HdmiDeviceInfo avr = getAvrDeviceInfo();
                         if (avr != null) {
                             onNewAvrAdded(avr);
+                        } else {
+                            setSystemAudioMode(false, true);
                         }
                     }
                 });
@@ -794,7 +799,8 @@
         if (getSystemAudioModeSetting() && !isSystemAudioActivated()) {
             addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
         }
-        if (isArcFeatureEnabled() && !hasAction(SetArcTransmissionStateAction.class)) {
+        if (isArcFeatureEnabled(avr.getPortId())
+                && !hasAction(SetArcTransmissionStateAction.class)) {
             startArcAction(true);
         }
     }
@@ -903,7 +909,7 @@
         // Should not activate ARC if +5V status is false.
         HdmiPortInfo portInfo = mService.getPortInfo(portId);
         if (portInfo.isArcSupported()) {
-            changeArcFeatureEnabled(isConnected);
+            changeArcFeatureEnabled(portId, isConnected);
         }
     }
 
@@ -915,20 +921,25 @@
     }
 
     /**
-     * Returns whether ARC is enabled or not.
+     * Returns true if ARC is currently established on a certain port.
      */
     @ServiceThreadOnly
-    boolean isArcEstabilished() {
+    boolean isArcEstablished() {
         assertRunOnServiceThread();
-        return mArcFeatureEnabled && mArcEstablished;
+        if (mArcEstablished) {
+            for (int i = 0; i < mArcFeatureEnabled.size(); i++) {
+                if (mArcFeatureEnabled.valueAt(i)) return true;
+            }
+        }
+        return false;
     }
 
     @ServiceThreadOnly
-    void changeArcFeatureEnabled(boolean enabled) {
+    void changeArcFeatureEnabled(int portId, boolean enabled) {
         assertRunOnServiceThread();
 
-        if (mArcFeatureEnabled != enabled) {
-            mArcFeatureEnabled = enabled;
+        if (mArcFeatureEnabled.get(portId) != enabled) {
+            mArcFeatureEnabled.put(portId, enabled);
             if (enabled) {
                 if (!mArcEstablished) {
                     startArcAction(true);
@@ -942,9 +953,9 @@
     }
 
     @ServiceThreadOnly
-    boolean isArcFeatureEnabled() {
+    boolean isArcFeatureEnabled(int portId) {
         assertRunOnServiceThread();
-        return mArcFeatureEnabled;
+        return mArcFeatureEnabled.get(portId);
     }
 
     @ServiceThreadOnly
@@ -1079,7 +1090,7 @@
                 && isConnectedToArcPort(avr.getPhysicalAddress())
                 && isDirectConnectAddress(avr.getPhysicalAddress())) {
             if (shouldCheckArcFeatureEnabled) {
-                return isArcFeatureEnabled();
+                return isArcFeatureEnabled(avr.getPortId());
             } else {
                 return true;
             }
@@ -1572,7 +1583,6 @@
     @Override
     @ServiceThreadOnly
     protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
-        super.disableDevice(initiatedByCec, callback);
         assertRunOnServiceThread();
         mService.unregisterTvInputCallback(mTvInputCallback);
         // Remove any repeated working actions.
@@ -1588,6 +1598,8 @@
 
         disableSystemAudioIfExist();
         disableArcIfExist();
+
+        super.disableDevice(initiatedByCec, callback);
         clearDeviceInfoList();
         checkIfPendingActionsCleared();
     }
@@ -1605,10 +1617,6 @@
         removeAction(SystemAudioAutoInitiationAction.class);
         removeAction(SystemAudioStatusAction.class);
         removeAction(VolumeControlAction.class);
-
-        // Turn off the mode but do not write it the settings, so that the next time TV powers on
-        // the system audio mode setting can be restored automatically.
-        setSystemAudioMode(false, false);
     }
 
     @ServiceThreadOnly
@@ -1621,7 +1629,7 @@
 
         // Seq #44.
         removeAction(RequestArcInitiationAction.class);
-        if (!hasAction(RequestArcTerminationAction.class) && isArcEstabilished()) {
+        if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) {
             addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress()));
         }
     }
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index f7555e9..a944a27 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -261,7 +261,7 @@
 
         // Turn off system audio mode and update settings.
         tv().setSystemAudioMode(false, true);
-        if (tv().isArcEstabilished()) {
+        if (tv().isArcEstablished()) {
             tv().setAudioReturnChannel(false);
             addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
         }
diff --git a/services/core/java/com/android/server/hdmi/RoutingControlAction.java b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
index ce5b9ab7..6c8694e 100644
--- a/services/core/java/com/android/server/hdmi/RoutingControlAction.java
+++ b/services/core/java/com/android/server/hdmi/RoutingControlAction.java
@@ -119,7 +119,7 @@
 
     private void handleReportPowerStatus(int devicePowerStatus) {
         if (isPowerOnOrTransient(getTvPowerStatus())) {
-            tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
+            updateActiveInput();
             if (isPowerOnOrTransient(devicePowerStatus)) {
                 sendSetStreamPath();
             }
@@ -127,6 +127,12 @@
         finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
     }
 
+    private void updateActiveInput() {
+        HdmiCecLocalDeviceTv tv = tv();
+        tv.setPrevPortId(tv.getActivePortId());
+        tv.updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
+    }
+
     private int getTvPowerStatus() {
         return tv().getPowerStatus();
     }
@@ -165,13 +171,13 @@
                         }
                     });
                 } else {
-                    tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
+                    updateActiveInput();
                     finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
                 }
                 return;
             case STATE_WAIT_FOR_REPORT_POWER_STATUS:
                 if (isPowerOnOrTransient(getTvPowerStatus())) {
-                    tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
+                    updateActiveInput();
                     sendSetStreamPath();
                 }
                 finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
@@ -189,7 +195,7 @@
             mState = STATE_WAIT_FOR_REPORT_POWER_STATUS;
             addTimer(mState, TIMEOUT_REPORT_POWER_STATUS_MS);
         } else {
-            tv().updateActiveInput(mCurrentRoutingPath, mNotifyInputChange);
+            updateActiveInput();
             sendSetStreamPath();
             finishWithCallback(HdmiControlManager.RESULT_SUCCESS);
         }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index d79b5fd..ecda36a 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -51,6 +51,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.app.IBatteryStats;
+import com.android.server.job.controllers.AppIdleController;
 import com.android.server.job.controllers.BatteryController;
 import com.android.server.job.controllers.ConnectivityController;
 import com.android.server.job.controllers.IdleController;
@@ -317,6 +318,7 @@
         mControllers.add(TimeController.get(this));
         mControllers.add(IdleController.get(this));
         mControllers.add(BatteryController.get(this));
+        mControllers.add(AppIdleController.get(this));
 
         mHandler = new JobHandler(context.getMainLooper());
         mJobSchedulerStub = new JobSchedulerStub();
@@ -688,7 +690,6 @@
             final boolean jobPending = mPendingJobs.contains(job);
             final boolean jobActive = isCurrentlyActiveLocked(job);
             final boolean userRunning = mStartedUsers.contains(job.getUserId());
-
             if (DEBUG) {
                 Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString()
                         + " ready=" + jobReady + " pending=" + jobPending
@@ -738,6 +739,10 @@
                         }
                     }
                     if (availableContext != null) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "About to run job "
+                                    + nextPending.getJob().getService().toString());
+                        }
                         if (!availableContext.executeRunnableJob(nextPending)) {
                             if (DEBUG) {
                                 Slog.d(TAG, "Error executing " + nextPending);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 63c8d92..53ceb2e 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -153,8 +153,9 @@
             }
 
             mRunningJob = job;
-            mParams = new JobParameters(this, job.getJobId(), job.getExtras(),
-                    !job.isConstraintsSatisfied());
+            final boolean isDeadlineExpired =
+                    job.getLatestRunTimeElapsed() >= SystemClock.elapsedRealtime();
+            mParams = new JobParameters(this, job.getJobId(), job.getExtras(), isDeadlineExpired);
             mExecutionStartTimeElapsed = SystemClock.elapsedRealtime();
 
             mVerb = VERB_BINDING;
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
new file mode 100644
index 0000000..8a9f3e1
--- /dev/null
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.job.controllers;
+
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.BatteryManagerInternal;
+import android.util.Slog;
+
+import com.android.server.LocalServices;
+import com.android.server.job.JobSchedulerService;
+import com.android.server.job.StateChangedListener;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Controls when apps are considered idle and if jobs pertaining to those apps should
+ * be executed. Apps that haven't been actively launched or accessed from a foreground app
+ * for a certain amount of time (maybe hours or days) are considered idle. When the app comes
+ * out of idle state, it will be allowed to run scheduled jobs.
+ */
+public class AppIdleController extends StateController
+        implements UsageStatsManagerInternal.AppIdleStateChangeListener {
+
+    private static final String LOG_TAG = "AppIdleController";
+    private static final boolean DEBUG = false;
+
+    // Singleton factory
+    private static Object sCreationLock = new Object();
+    private static volatile AppIdleController sController;
+    final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
+    private final UsageStatsManagerInternal mUsageStatsInternal;
+    private final BatteryManagerInternal mBatteryManagerInternal;
+    private boolean mPluggedIn;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+                int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+                // TODO: Allow any charger type
+                onPluggedIn((plugged & BatteryManager.BATTERY_PLUGGED_AC) != 0);
+            }
+        }
+    };
+
+    public static AppIdleController get(JobSchedulerService service) {
+        synchronized (sCreationLock) {
+            if (sController == null) {
+                sController = new AppIdleController(service, service.getContext());
+            }
+            return sController;
+        }
+    }
+
+    private AppIdleController(StateChangedListener stateChangedListener, Context context) {
+        super(stateChangedListener, context);
+        mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
+        mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
+        mPluggedIn = isPowered();
+        mUsageStatsInternal.addAppIdleStateChangeListener(this);
+        registerReceivers();
+    }
+
+    private void registerReceivers() {
+        // Monitor battery charging state
+        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
+    private boolean isPowered() {
+        // TODO: Allow any charger type
+        return mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_AC);
+    }
+
+    @Override
+    public void maybeStartTrackingJob(JobStatus jobStatus) {
+        synchronized (mTrackedTasks) {
+            mTrackedTasks.add(jobStatus);
+            String packageName = jobStatus.job.getService().getPackageName();
+            final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
+                    jobStatus.getUserId());
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Start tracking, setting idle state of "
+                        + packageName + " to " + appIdle);
+            }
+            jobStatus.appNotIdleConstraintSatisfied.set(!appIdle);
+        }
+    }
+
+    @Override
+    public void maybeStopTrackingJob(JobStatus jobStatus) {
+        synchronized (mTrackedTasks) {
+            mTrackedTasks.remove(jobStatus);
+        }
+    }
+
+    @Override
+    public void dumpControllerState(PrintWriter pw) {
+        // TODO:
+    }
+
+    @Override
+    public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+        boolean changed = false;
+        synchronized (mTrackedTasks) {
+            // If currently plugged in, we don't care about app idle state
+            if (mPluggedIn) {
+                return;
+            }
+            for (JobStatus task : mTrackedTasks) {
+                if (task.job.getService().getPackageName().equals(packageName)
+                        && task.getUserId() == userId) {
+                    if (task.appNotIdleConstraintSatisfied.get() != !idle) {
+                        if (DEBUG) {
+                            Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+                                    + packageName + " to " + idle);
+                        }
+                        task.appNotIdleConstraintSatisfied.set(!idle);
+                        changed = true;
+                    }
+                }
+            }
+        }
+        if (changed) {
+            mStateChangedListener.onControllerStateChanged();
+        }
+    }
+
+    void onPluggedIn(boolean pluggedIn) {
+        // Flag if any app's idle state has changed
+        boolean changed = false;
+        synchronized (mTrackedTasks) {
+            if (mPluggedIn == pluggedIn) {
+                return;
+            }
+            mPluggedIn = pluggedIn;
+            for (JobStatus task : mTrackedTasks) {
+                String packageName = task.job.getService().getPackageName();
+                final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
+                        task.getUserId());
+                if (DEBUG) {
+                    Slog.d(LOG_TAG, "Plugged in " + pluggedIn + ", setting idle state of "
+                            + packageName + " to " + appIdle);
+                }
+                if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
+                    task.appNotIdleConstraintSatisfied.set(!appIdle);
+                    changed = true;
+                }
+            }
+        }
+        if (changed) {
+            mStateChangedListener.onControllerStateChanged();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/job/controllers/BatteryController.java b/services/core/java/com/android/server/job/controllers/BatteryController.java
index 309e034..7c2aead 100644
--- a/services/core/java/com/android/server/job/controllers/BatteryController.java
+++ b/services/core/java/com/android/server/job/controllers/BatteryController.java
@@ -47,10 +47,6 @@
 
     private static final Object sCreationLock = new Object();
     private static volatile BatteryController sController;
-    private static final String ACTION_CHARGING_STABLE =
-            "com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE";
-    /** Wait this long after phone is plugged in before doing any work. */
-    private static final long STABLE_CHARGING_THRESHOLD_MILLIS = 2 * 60 * 1000; // 2 minutes.
 
     private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     private ChargingTracker mChargeTracker;
@@ -91,9 +87,6 @@
                 taskStatus.chargingConstraintSatisfied.set(isOnStablePower);
             }
         }
-        if (isOnStablePower) {
-            mChargeTracker.setStableChargingAlarm();
-        }
     }
 
     @Override
@@ -131,8 +124,6 @@
     }
 
     public class ChargingTracker extends BroadcastReceiver {
-        private final AlarmManager mAlarm;
-        private final PendingIntent mStableChargingTriggerIntent;
         /**
          * Track whether we're "charging", where charging means that we're ready to commit to
          * doing work.
@@ -142,9 +133,6 @@
         private boolean mBatteryHealthy;
 
         public ChargingTracker() {
-            mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-            Intent intent = new Intent(ACTION_CHARGING_STABLE);
-            mStableChargingTriggerIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
         }
 
         public void startTracking() {
@@ -154,10 +142,8 @@
             filter.addAction(Intent.ACTION_BATTERY_LOW);
             filter.addAction(Intent.ACTION_BATTERY_OKAY);
             // Charging/not charging.
-            filter.addAction(Intent.ACTION_POWER_CONNECTED);
-            filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
-            // Charging stable.
-            filter.addAction(ACTION_CHARGING_STABLE);
+            filter.addAction(BatteryManager.ACTION_CHARGING);
+            filter.addAction(BatteryManager.ACTION_DISCHARGING);
             mContext.registerReceiver(this, filter);
 
             // Initialise tracker state.
@@ -195,45 +181,21 @@
                 }
                 mBatteryHealthy = true;
                 maybeReportNewChargingState();
-            } else if (Intent.ACTION_POWER_CONNECTED.equals(action)) {
+            } else if (BatteryManager.ACTION_CHARGING.equals(action)) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Received charging intent, setting alarm for "
-                            + STABLE_CHARGING_THRESHOLD_MILLIS);
+                    Slog.d(TAG, "Received charging intent, fired @ "
+                            + SystemClock.elapsedRealtime());
                 }
-                // Set up an alarm for ACTION_CHARGING_STABLE - we don't want to kick off tasks
-                // here if the user unplugs the phone immediately.
-                setStableChargingAlarm();
                 mCharging = true;
-            } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) {
+                maybeReportNewChargingState();
+            } else if (BatteryManager.ACTION_DISCHARGING.equals(action)) {
                 if (DEBUG) {
-                    Slog.d(TAG, "Disconnected from power, cancelling any set alarms.");
+                    Slog.d(TAG, "Disconnected from power.");
                 }
-                // If an alarm is set, breathe a sigh of relief and cancel it - crisis averted.
-                mAlarm.cancel(mStableChargingTriggerIntent);
                 mCharging = false;
                 maybeReportNewChargingState();
-            }else if (ACTION_CHARGING_STABLE.equals(action)) {
-                // Here's where we actually do the notify for a task being ready.
-                if (DEBUG) {
-                    Slog.d(TAG, "Stable charging fired @ " + SystemClock.elapsedRealtime()
-                            + " charging: " + mCharging);
-                }
-                if (mCharging) {  // Should never receive this intent if mCharging is false.
-                    maybeReportNewChargingState();
-                }
             }
         }
-
-        void setStableChargingAlarm() {
-            final long alarmTriggerElapsed =
-                    SystemClock.elapsedRealtime() + STABLE_CHARGING_THRESHOLD_MILLIS;
-            if (DEBUG) {
-                Slog.d(TAG, "Setting stable alarm to go off in " +
-                        (STABLE_CHARGING_THRESHOLD_MILLIS / 1000) + "s");
-            }
-            mAlarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTriggerElapsed,
-                    mStableChargingTriggerIntent);
-        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index e3c55b6..69c63f3 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -54,6 +54,7 @@
     final AtomicBoolean idleConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean unmeteredConstraintSatisfied = new AtomicBoolean();
     final AtomicBoolean connectivityConstraintSatisfied = new AtomicBoolean();
+    final AtomicBoolean appNotIdleConstraintSatisfied = new AtomicBoolean();
 
     /**
      * Earliest point in the future at which this job will be eligible to run. A value of 0
@@ -199,8 +200,11 @@
      * the constraints are satisfied <strong>or</strong> the deadline on the job has expired.
      */
     public synchronized boolean isReady() {
-        return isConstraintsSatisfied()
-                || (hasDeadlineConstraint() && deadlineConstraintSatisfied.get());
+        // Deadline constraint trumps other constraints
+        // AppNotIdle implicit constraint trumps all!
+        return (isConstraintsSatisfied()
+                    || (hasDeadlineConstraint() && deadlineConstraintSatisfied.get()))
+                && appNotIdleConstraintSatisfied.get();
     }
 
     /**
@@ -229,6 +233,7 @@
                 + ",N=" + job.getNetworkType() + ",C=" + job.isRequireCharging()
                 + ",I=" + job.isRequireDeviceIdle() + ",F=" + numFailures
                 + ",P=" + job.isPersisted()
+                + ",ANI=" + appNotIdleConstraintSatisfied.get()
                 + (isReady() ? "(READY)" : "")
                 + "]";
     }
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index efd1928..cda7c32 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -44,7 +44,7 @@
 
     /**
      * Implement the logic here to decide whether a job should be tracked by this controller.
-     * This logic is put here so the JobManger can be completely agnostic of Controller logic.
+     * This logic is put here so the JobManager can be completely agnostic of Controller logic.
      * Also called when updating a task, so implementing controllers have to be aware of
      * preexisting tasks.
      */
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 4c6cb17..b3d7287 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -91,14 +91,20 @@
     public synchronized void maybeStartTrackingJob(JobStatus job) {
         if (job.hasTimingDelayConstraint() || job.hasDeadlineConstraint()) {
             maybeStopTrackingJob(job);
+            boolean isInsert = false;
             ListIterator<JobStatus> it = mTrackedJobs.listIterator(mTrackedJobs.size());
             while (it.hasPrevious()) {
                 JobStatus ts = it.previous();
                 if (ts.getLatestRunTimeElapsed() < job.getLatestRunTimeElapsed()) {
                     // Insert
+                    isInsert = true;
                     break;
                 }
             }
+            if(isInsert)
+            {
+                it.next();
+            }
             it.add(job);
             maybeUpdateAlarms(
                     job.hasTimingDelayConstraint() ? job.getEarliestRunTime() : Long.MAX_VALUE,
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 9dcc529..2da9d8e 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -106,7 +106,8 @@
                 mMode = mode;
                 mOnMS = onMS;
                 mOffMS = offMS;
-                Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")");
+                Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
+                        + Integer.toHexString(color) + ")");
                 try {
                     setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
                 } finally {
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index a415a84..15b68c7 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -571,7 +571,7 @@
     }
 
     private static boolean isAccessibleToUser(int uid, int callerUid) {
-        return callerUid == android.os.Process.SYSTEM_UID ||
+        return UserHandle.getAppId(callerUid) == android.os.Process.SYSTEM_UID ||
                 uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING
                 || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid);
     }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index ab53fbc..fc2eced 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -25,12 +25,10 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.provider.Settings.Global;
 import android.service.notification.Condition;
 import android.service.notification.ConditionProviderService;
 import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
-import android.service.notification.ZenModeConfig;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -41,50 +39,44 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Objects;
 
 public class ConditionProviders extends ManagedServices {
-    private static final Condition[] NO_CONDITIONS = new Condition[0];
+    private final ArrayList<ConditionRecord> mRecords = new ArrayList<>();
+    private final ArrayMap<IBinder, IConditionListener> mListeners = new ArrayMap<>();
+    private final ArraySet<String> mSystemConditionProviderNames;
+    private final ArraySet<SystemConditionProviderService> mSystemConditionProviders
+            = new ArraySet<>();
 
-    private final ZenModeHelper mZenModeHelper;
-    private final ArrayMap<IBinder, IConditionListener> mListeners
-            = new ArrayMap<IBinder, IConditionListener>();
-    private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
-    private final ArraySet<String> mSystemConditionProviders;
-    private final CountdownConditionProvider mCountdown;
-    private final DowntimeConditionProvider mDowntime;
-    private final NextAlarmConditionProvider mNextAlarm;
-    private final NextAlarmTracker mNextAlarmTracker;
+    private Callback mCallback;
 
-    private Condition mExitCondition;
-    private ComponentName mExitConditionComponent;
-
-    public ConditionProviders(Context context, Handler handler,
-            UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
+    public ConditionProviders(Context context, Handler handler, UserProfiles userProfiles) {
         super(context, handler, new Object(), userProfiles);
-        mZenModeHelper = zenModeHelper;
-        mZenModeHelper.addCallback(new ZenModeHelperCallback());
-        mSystemConditionProviders = safeSet(PropConfig.getStringArray(mContext,
+        mSystemConditionProviderNames = safeSet(PropConfig.getStringArray(mContext,
                 "system.condition.providers",
                 R.array.config_system_condition_providers));
-        final boolean countdown = mSystemConditionProviders.contains(ZenModeConfig.COUNTDOWN_PATH);
-        final boolean downtime = mSystemConditionProviders.contains(ZenModeConfig.DOWNTIME_PATH);
-        final boolean nextAlarm = mSystemConditionProviders.contains(ZenModeConfig.NEXT_ALARM_PATH);
-        mNextAlarmTracker = (downtime || nextAlarm) ? new NextAlarmTracker(mContext) : null;
-        mCountdown = countdown ? new CountdownConditionProvider() : null;
-        mDowntime = downtime ? new DowntimeConditionProvider(this, mNextAlarmTracker,
-                mZenModeHelper) : null;
-        mNextAlarm = nextAlarm ? new NextAlarmConditionProvider(mNextAlarmTracker) : null;
-        loadZenConfig();
     }
 
-    public boolean isSystemConditionProviderEnabled(String path) {
-        return mSystemConditionProviders.contains(path);
+    public void setCallback(Callback callback) {
+        mCallback = callback;
+    }
+
+    public boolean isSystemProviderEnabled(String path) {
+        return mSystemConditionProviderNames.contains(path);
+    }
+
+    public void addSystemProvider(SystemConditionProviderService service) {
+        mSystemConditionProviders.add(service);
+        service.attachBase(mContext);
+        registerService(service.asInterface(), service.getComponent(), UserHandle.USER_OWNER);
+    }
+
+    public Iterable<SystemConditionProviderService> getSystemProviders() {
+        return mSystemConditionProviders;
     }
 
     @Override
     protected Config getConfig() {
-        Config c = new Config();
+        final Config c = new Config();
         c.caption = "condition provider";
         c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
         c.secureSettingName = Settings.Secure.ENABLED_CONDITION_PROVIDERS;
@@ -98,12 +90,6 @@
     public void dump(PrintWriter pw, DumpFilter filter) {
         super.dump(pw, filter);
         synchronized(mMutex) {
-            if (filter == null) {
-                pw.print("    mListeners("); pw.print(mListeners.size()); pw.println("):");
-                for (int i = 0; i < mListeners.size(); i++) {
-                    pw.print("      "); pw.println(mListeners.keyAt(i));
-                }
-            }
             pw.print("    mRecords("); pw.print(mRecords.size()); pw.println("):");
             for (int i = 0; i < mRecords.size(); i++) {
                 final ConditionRecord r = mRecords.get(i);
@@ -115,18 +101,15 @@
                 }
             }
         }
-        pw.print("    mSystemConditionProviders: "); pw.println(mSystemConditionProviders);
-        if (mCountdown != null) {
-            mCountdown.dump(pw, filter);
+        if (filter == null) {
+            pw.print("    mListeners("); pw.print(mListeners.size()); pw.println("):");
+            for (int i = 0; i < mListeners.size(); i++) {
+                pw.print("      "); pw.println(mListeners.keyAt(i));
+            }
         }
-        if (mDowntime != null) {
-            mDowntime.dump(pw, filter);
-        }
-        if (mNextAlarm != null) {
-            mNextAlarm.dump(pw, filter);
-        }
-        if (mNextAlarmTracker != null) {
-            mNextAlarmTracker.dump(pw, filter);
+        pw.print("    mSystemConditionProviders: "); pw.println(mSystemConditionProviderNames);
+        for (int i = 0; i < mSystemConditionProviders.size(); i++) {
+            mSystemConditionProviders.valueAt(i).dump(pw, filter);
         }
     }
 
@@ -138,31 +121,16 @@
     @Override
     public void onBootPhaseAppsCanStart() {
         super.onBootPhaseAppsCanStart();
-        if (mNextAlarmTracker != null) {
-            mNextAlarmTracker.init();
-        }
-        if (mCountdown != null) {
-            mCountdown.attachBase(mContext);
-            registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
-                    UserHandle.USER_OWNER);
-        }
-        if (mDowntime != null) {
-            mDowntime.attachBase(mContext);
-            registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
-                    UserHandle.USER_OWNER);
-        }
-        if (mNextAlarm != null) {
-            mNextAlarm.attachBase(mContext);
-            registerService(mNextAlarm.asInterface(), NextAlarmConditionProvider.COMPONENT,
-                    UserHandle.USER_OWNER);
+        if (mCallback != null) {
+            mCallback.onBootComplete();
         }
     }
 
     @Override
     public void onUserSwitched() {
         super.onUserSwitched();
-        if (mNextAlarmTracker != null) {
-            mNextAlarmTracker.onUserSwitched();
+        if (mCallback != null) {
+            mCallback.onUserSwitched();
         }
     }
 
@@ -174,24 +142,6 @@
         } catch (RemoteException e) {
             // we tried
         }
-        synchronized (mMutex) {
-            if (info.component.equals(mExitConditionComponent)) {
-                // ensure record exists, we'll wire it up and subscribe below
-                final ConditionRecord manualRecord =
-                        getRecordLocked(mExitCondition.id, mExitConditionComponent);
-                manualRecord.isManual = true;
-            }
-            final int N = mRecords.size();
-            for(int i = 0; i < N; i++) {
-                final ConditionRecord r = mRecords.get(i);
-                if (!r.component.equals(info.component)) continue;
-                r.info = info;
-                // if automatic or manual, auto-subscribe
-                if (r.isAutomatic || r.isManual) {
-                    subscribeLocked(r);
-                }
-            }
-        }
     }
 
     @Override
@@ -200,15 +150,6 @@
         for (int i = mRecords.size() - 1; i >= 0; i--) {
             final ConditionRecord r = mRecords.get(i);
             if (!r.component.equals(removed.component)) continue;
-            if (r.isManual) {
-                // removing the current manual condition, exit zen
-                onManualConditionClearing();
-                mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved");
-            }
-            if (r.isAutomatic) {
-                // removing an automatic condition, exit zen
-                mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "automaticServiceRemoved");
-            }
             mRecords.remove(i);
         }
     }
@@ -219,9 +160,9 @@
         }
     }
 
-    public void requestZenModeConditions(IConditionListener callback, int relevance) {
+    public void requestConditions(IConditionListener callback, int relevance) {
         synchronized(mMutex) {
-            if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
+            if (DEBUG) Slog.d(TAG, "requestConditions callback=" + callback
                     + " relevance=" + Condition.relevanceToString(relevance));
             if (callback == null) return;
             relevance = relevance & (Condition.FLAG_RELEVANT_NOW | Condition.FLAG_RELEVANT_ALWAYS);
@@ -262,7 +203,8 @@
         return rt;
     }
 
-    private ConditionRecord getRecordLocked(Uri id, ComponentName component) {
+    private ConditionRecord getRecordLocked(Uri id, ComponentName component, boolean create) {
+        if (id == null || component == null) return null;
         final int N = mRecords.size();
         for (int i = 0; i < N; i++) {
             final ConditionRecord r = mRecords.get(i);
@@ -270,9 +212,12 @@
                 return r;
             }
         }
-        final ConditionRecord r = new ConditionRecord(id, component);
-        mRecords.add(r);
-        return r;
+        if (create) {
+            final ConditionRecord r = new ConditionRecord(id, component);
+            mRecords.add(r);
+            return r;
+        }
+        return null;
     }
 
     public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
@@ -291,99 +236,48 @@
             }
             for (int i = 0; i < N; i++) {
                 final Condition c = conditions[i];
-                final ConditionRecord r = getRecordLocked(c.id, info.component);
-                final Condition oldCondition = r.condition;
-                final boolean conditionUpdate = oldCondition != null && !oldCondition.equals(c);
+                final ConditionRecord r = getRecordLocked(c.id, info.component, true /*create*/);
                 r.info = info;
                 r.condition = c;
-                // if manual, exit zen if false (or failed), update if true (and changed)
-                if (r.isManual) {
-                    if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
-                        final boolean failed = c.state == Condition.STATE_ERROR;
-                        if (failed) {
-                            Slog.w(TAG, "Exit zen: manual condition failed: " + c);
-                        } else if (DEBUG) {
-                            Slog.d(TAG, "Exit zen: manual condition false: " + c);
-                        }
-                        onManualConditionClearing();
-                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
-                                "manualConditionExit");
-                        unsubscribeLocked(r);
-                        r.isManual = false;
-                    } else if (c.state == Condition.STATE_TRUE && conditionUpdate) {
-                        if (DEBUG) Slog.d(TAG, "Current condition updated, still true. old="
-                                + oldCondition + " new=" + c);
-                        setZenModeCondition(c, "conditionUpdate");
-                    }
-                }
-                // if automatic, exit zen if false (or failed), enter zen if true
-                if (r.isAutomatic) {
-                    if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
-                        final boolean failed = c.state == Condition.STATE_ERROR;
-                        if (failed) {
-                            Slog.w(TAG, "Exit zen: automatic condition failed: " + c);
-                        } else if (DEBUG) {
-                            Slog.d(TAG, "Exit zen: automatic condition false: " + c);
-                        }
-                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
-                                "automaticConditionExit");
-                    } else if (c.state == Condition.STATE_TRUE) {
-                        Slog.d(TAG, "Enter zen: automatic condition true: " + c);
-                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
-                                "automaticConditionEnter");
-                    }
+                if (mCallback != null) {
+                    mCallback.onConditionChanged(c.id, c);
                 }
             }
         }
     }
 
-    private void ensureRecordExists(Condition condition, IConditionProvider provider,
-            ComponentName component) {
+    public void ensureRecordExists(ComponentName component, Uri conditionId,
+            IConditionProvider provider) {
         // constructed by convention, make sure the record exists...
-        final ConditionRecord r = getRecordLocked(condition.id, component);
+        final ConditionRecord r = getRecordLocked(conditionId, component, true /*create*/);
         if (r.info == null) {
             // ... and is associated with the in-process service
             r.info = checkServiceTokenLocked(provider);
         }
     }
 
-    public void setZenModeCondition(Condition condition, String reason) {
-        if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition + " reason=" + reason);
-        synchronized(mMutex) {
-            ComponentName conditionComponent = null;
-            if (condition != null) {
-                if (mCountdown != null && ZenModeConfig.isValidCountdownConditionId(condition.id)) {
-                    ensureRecordExists(condition, mCountdown.asInterface(),
-                            CountdownConditionProvider.COMPONENT);
-                }
-                if (mDowntime != null && ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
-                    ensureRecordExists(condition, mDowntime.asInterface(),
-                            DowntimeConditionProvider.COMPONENT);
-                }
+    public boolean subscribeIfNecessary(ComponentName component, Uri conditionId) {
+        synchronized (mMutex) {
+            final ConditionRecord r = getRecordLocked(conditionId, component, false /*create*/);
+            if (r == null) {
+                Slog.w(TAG, "Unable to subscribe to " + component + " " + conditionId);
+                return false;
             }
-            final int N = mRecords.size();
-            for (int i = 0; i < N; i++) {
-                final ConditionRecord r = mRecords.get(i);
-                final boolean idEqual = condition != null && r.id.equals(condition.id);
-                if (r.isManual && !idEqual) {
-                    // was previous manual condition, unsubscribe
-                    unsubscribeLocked(r);
-                    r.isManual = false;
-                } else if (idEqual && !r.isManual) {
-                    // is new manual condition, subscribe
-                    subscribeLocked(r);
-                    r.isManual = true;
-                }
-                if (idEqual) {
-                    conditionComponent = r.component;
-                }
+            if (r.subscribed) return true;
+            subscribeLocked(r);
+            return r.subscribed;
+        }
+    }
+
+    public void unsubscribeIfNecessary(ComponentName component, Uri conditionId) {
+        synchronized (mMutex) {
+            final ConditionRecord r = getRecordLocked(conditionId, component, false /*create*/);
+            if (r == null) {
+                Slog.w(TAG, "Unable to unsubscribe to " + component + " " + conditionId);
+                return;
             }
-            if (!Objects.equals(mExitCondition, condition)) {
-                mExitCondition = condition;
-                mExitConditionComponent = conditionComponent;
-                ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, reason);
-                saveZenConfigLocked();
-            }
+            if (!r.subscribed) return;
+            unsubscribeLocked(r);;
         }
     }
 
@@ -393,8 +287,9 @@
         RemoteException re = null;
         if (provider != null) {
             try {
-                Slog.d(TAG, "Subscribing to " + r.id + " with " + provider);
+                Slog.d(TAG, "Subscribing to " + r.id + " with " + r.component);
                 provider.onSubscribe(r.id);
+                r.subscribed = true;
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error subscribing to " + r, e);
                 re = e;
@@ -417,53 +312,6 @@
         return rt;
     }
 
-    public void setAutomaticZenModeConditions(Uri[] conditionIds) {
-        setAutomaticZenModeConditions(conditionIds, true /*save*/);
-    }
-
-    private void setAutomaticZenModeConditions(Uri[] conditionIds, boolean save) {
-        if (DEBUG) Slog.d(TAG, "setAutomaticZenModeConditions "
-                + (conditionIds == null ? null : Arrays.asList(conditionIds)));
-        synchronized(mMutex) {
-            final ArraySet<Uri> newIds = safeSet(conditionIds);
-            final int N = mRecords.size();
-            boolean changed = false;
-            for (int i = 0; i < N; i++) {
-                final ConditionRecord r = mRecords.get(i);
-                final boolean automatic = newIds.contains(r.id);
-                if (!r.isAutomatic && automatic) {
-                    // subscribe to new automatic
-                    subscribeLocked(r);
-                    r.isAutomatic = true;
-                    changed = true;
-                } else if (r.isAutomatic && !automatic) {
-                    // unsubscribe from old automatic
-                    unsubscribeLocked(r);
-                    r.isAutomatic = false;
-                    changed = true;
-                }
-            }
-            if (save && changed) {
-                saveZenConfigLocked();
-            }
-        }
-    }
-
-    public Condition[] getAutomaticZenModeConditions() {
-        synchronized(mMutex) {
-            final int N = mRecords.size();
-            ArrayList<Condition> rt = null;
-            for (int i = 0; i < N; i++) {
-                final ConditionRecord r = mRecords.get(i);
-                if (r.isAutomatic && r.condition != null) {
-                    if (rt == null) rt = new ArrayList<Condition>();
-                    rt.add(r.condition);
-                }
-            }
-            return rt == null ? NO_CONDITIONS : rt.toArray(new Condition[rt.size()]);
-        }
-    }
-
     private void unsubscribeLocked(ConditionRecord r) {
         if (DEBUG) Slog.d(TAG, "unsubscribeLocked " + r);
         final IConditionProvider provider = provider(r);
@@ -475,6 +323,7 @@
                 Slog.w(TAG, "Error unsubscribing to " + r, e);
                 re = e;
             }
+            r.subscribed = false;
         }
         ZenLog.traceUnsubscribe(r != null ? r.id : null, provider, re);
     }
@@ -495,7 +344,7 @@
             for (int i = mRecords.size() - 1; i >= 0; i--) {
                 final ConditionRecord r = mRecords.get(i);
                 if (r.info != info) continue;
-                if (r.isManual || r.isAutomatic) continue;
+                if (r.subscribed) continue;
                 mRecords.remove(i);
             }
             try {
@@ -506,103 +355,12 @@
         }
     }
 
-    private void loadZenConfig() {
-        final ZenModeConfig config = mZenModeHelper.getConfig();
-        if (config == null) {
-            if (DEBUG) Slog.d(TAG, "loadZenConfig: no config");
-            return;
-        }
-        synchronized (mMutex) {
-            final boolean changingExit = !Objects.equals(mExitCondition, config.exitCondition);
-            mExitCondition = config.exitCondition;
-            mExitConditionComponent = config.exitConditionComponent;
-            if (changingExit) {
-                ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config");
-            }
-            if (mDowntime != null) {
-                mDowntime.setConfig(config);
-            }
-            if (config.conditionComponents == null || config.conditionIds == null
-                    || config.conditionComponents.length != config.conditionIds.length) {
-                if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
-                setAutomaticZenModeConditions(null, false /*save*/);
-                return;
-            }
-            final ArraySet<Uri> newIds = new ArraySet<Uri>();
-            final int N = config.conditionComponents.length;
-            for (int i = 0; i < N; i++) {
-                final ComponentName component = config.conditionComponents[i];
-                final Uri id = config.conditionIds[i];
-                if (component != null && id != null) {
-                    getRecordLocked(id, component);  // ensure record exists
-                    newIds.add(id);
-                }
-            }
-            if (DEBUG) Slog.d(TAG, "loadZenConfig: N=" + N);
-            setAutomaticZenModeConditions(newIds.toArray(new Uri[newIds.size()]), false /*save*/);
-        }
-    }
-
-    private void saveZenConfigLocked() {
-        ZenModeConfig config = mZenModeHelper.getConfig();
-        if (config == null) return;
-        config = config.copy();
-        final ArrayList<ConditionRecord> automatic = new ArrayList<ConditionRecord>();
-        final int automaticN = mRecords.size();
-        for (int i = 0; i < automaticN; i++) {
-            final ConditionRecord r = mRecords.get(i);
-            if (r.isAutomatic) {
-                automatic.add(r);
-            }
-        }
-        if (automatic.isEmpty()) {
-            config.conditionComponents = null;
-            config.conditionIds = null;
-        } else {
-            final int N = automatic.size();
-            config.conditionComponents = new ComponentName[N];
-            config.conditionIds = new Uri[N];
-            for (int i = 0; i < N; i++) {
-                final ConditionRecord r = automatic.get(i);
-                config.conditionComponents[i] = r.component;
-                config.conditionIds[i] = r.id;
-            }
-        }
-        config.exitCondition = mExitCondition;
-        config.exitConditionComponent = mExitConditionComponent;
-        if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
-        mZenModeHelper.setConfig(config);
-    }
-
-    private void onManualConditionClearing() {
-        if (mDowntime != null) {
-            mDowntime.onManualConditionClearing();
-        }
-    }
-
-    private class ZenModeHelperCallback extends ZenModeHelper.Callback {
-        @Override
-        void onConfigChanged() {
-            loadZenConfig();
-        }
-
-        @Override
-        void onZenModeChanged() {
-            final int mode = mZenModeHelper.getZenMode();
-            if (mode == Global.ZEN_MODE_OFF) {
-                // ensure any manual condition is cleared
-                setZenModeCondition(null, "zenOff");
-            }
-        }
-    }
-
     private static class ConditionRecord {
         public final Uri id;
         public final ComponentName component;
         public Condition condition;
         public ManagedServiceInfo info;
-        public boolean isAutomatic;
-        public boolean isManual;
+        public boolean subscribed;
 
         private ConditionRecord(Uri id, ComponentName component) {
             this.id = id;
@@ -612,10 +370,16 @@
         @Override
         public String toString() {
             final StringBuilder sb = new StringBuilder("ConditionRecord[id=")
-                    .append(id).append(",component=").append(component);
-            if (isAutomatic) sb.append(",automatic");
-            if (isManual) sb.append(",manual");
+                    .append(id).append(",component=").append(component)
+                    .append(",subscribed=").append(subscribed);
             return sb.append(']').toString();
         }
     }
+
+    public interface Callback {
+        void onBootComplete();
+        void onConditionChanged(Uri id, Condition condition);
+        void onUserSwitched();
+    }
+
 }
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index 37aacaa..d223353 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -25,7 +25,6 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.service.notification.Condition;
-import android.service.notification.ConditionProviderService;
 import android.service.notification.IConditionProvider;
 import android.service.notification.ZenModeConfig;
 import android.text.format.DateUtils;
@@ -38,7 +37,7 @@
 import java.util.Date;
 
 /** Built-in zen condition provider for simple time-based conditions */
-public class CountdownConditionProvider extends ConditionProviderService {
+public class CountdownConditionProvider extends SystemConditionProviderService {
     private static final String TAG = "CountdownConditions";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -59,6 +58,27 @@
         if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
     }
 
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+
+    @Override
+    public boolean isValidConditionid(Uri id) {
+        return ZenModeConfig.isValidCountdownConditionId(id);
+    }
+
+    @Override
+    public void attachBase(Context base) {
+        attachBaseContext(base);
+    }
+
+    @Override
+    public IConditionProvider asInterface() {
+        return (IConditionProvider) onBind(null);
+    }
+
+    @Override
     public void dump(PrintWriter pw, DumpFilter filter) {
         pw.println("    CountdownConditionProvider:");
         pw.print("      mConnected="); pw.println(mConnected);
@@ -154,11 +174,4 @@
         return new Date(time) + " (" + time + ")";
     }
 
-    public void attachBase(Context base) {
-        attachBaseContext(base);
-    }
-
-    public IConditionProvider asInterface() {
-        return (IConditionProvider) onBind(null);
-    }
 }
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
deleted file mode 100644
index df4ecfd..0000000
--- a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.notification;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.AlarmManager.AlarmClockInfo;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.Uri;
-import android.provider.Settings.Global;
-import android.service.notification.Condition;
-import android.service.notification.ConditionProviderService;
-import android.service.notification.IConditionProvider;
-import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.DowntimeInfo;
-import android.text.format.DateFormat;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.TimeUtils;
-
-import com.android.internal.R;
-import com.android.server.notification.NotificationManagerService.DumpFilter;
-
-import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.TimeZone;
-
-/** Built-in zen condition provider for managing downtime */
-public class DowntimeConditionProvider extends ConditionProviderService {
-    private static final String TAG = "DowntimeConditions";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    public static final ComponentName COMPONENT =
-            new ComponentName("android", DowntimeConditionProvider.class.getName());
-
-    private static final String ENTER_ACTION = TAG + ".enter";
-    private static final int ENTER_CODE = 100;
-    private static final String EXIT_ACTION = TAG + ".exit";
-    private static final int EXIT_CODE = 101;
-    private static final String EXTRA_TIME = "time";
-
-    private static final long SECONDS = 1000;
-    private static final long MINUTES = 60 * SECONDS;
-    private static final long HOURS = 60 * MINUTES;
-
-    private final Context mContext = this;
-    private final DowntimeCalendar mCalendar = new DowntimeCalendar();
-    private final FiredAlarms mFiredAlarms = new FiredAlarms();
-    private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
-    private final ConditionProviders mConditionProviders;
-    private final NextAlarmTracker mTracker;
-    private final ZenModeHelper mZenModeHelper;
-
-    private boolean mConnected;
-    private long mLookaheadThreshold;
-    private ZenModeConfig mConfig;
-    private boolean mDowntimed;
-    private boolean mConditionClearing;
-    private boolean mRequesting;
-
-    public DowntimeConditionProvider(ConditionProviders conditionProviders,
-            NextAlarmTracker tracker, ZenModeHelper zenModeHelper) {
-        if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()");
-        mConditionProviders = conditionProviders;
-        mTracker = tracker;
-        mZenModeHelper = zenModeHelper;
-    }
-
-    public void dump(PrintWriter pw, DumpFilter filter) {
-        pw.println("    DowntimeConditionProvider:");
-        pw.print("      mConnected="); pw.println(mConnected);
-        pw.print("      mSubscriptions="); pw.println(mSubscriptions);
-        pw.print("      mLookaheadThreshold="); pw.print(mLookaheadThreshold);
-        pw.print(" ("); TimeUtils.formatDuration(mLookaheadThreshold, pw); pw.println(")");
-        pw.print("      mCalendar="); pw.println(mCalendar);
-        pw.print("      mFiredAlarms="); pw.println(mFiredAlarms);
-        pw.print("      mDowntimed="); pw.println(mDowntimed);
-        pw.print("      mConditionClearing="); pw.println(mConditionClearing);
-        pw.print("      mRequesting="); pw.println(mRequesting);
-    }
-
-    public void attachBase(Context base) {
-        attachBaseContext(base);
-    }
-
-    public IConditionProvider asInterface() {
-        return (IConditionProvider) onBind(null);
-    }
-
-    @Override
-    public void onConnected() {
-        if (DEBUG) Slog.d(TAG, "onConnected");
-        mConnected = true;
-        mLookaheadThreshold = PropConfig.getInt(mContext, "downtime.condition.lookahead",
-                R.integer.config_downtime_condition_lookahead_threshold_hrs) * HOURS;
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(ENTER_ACTION);
-        filter.addAction(EXIT_ACTION);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
-        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        mContext.registerReceiver(mReceiver, filter);
-        mTracker.addCallback(mTrackerCallback);
-        mZenModeHelper.addCallback(mZenCallback);
-        init();
-    }
-
-    @Override
-    public void onDestroy() {
-        if (DEBUG) Slog.d(TAG, "onDestroy");
-        mTracker.removeCallback(mTrackerCallback);
-        mZenModeHelper.removeCallback(mZenCallback);
-        mConnected = false;
-    }
-
-    @Override
-    public void onRequestConditions(int relevance) {
-        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
-        if (!mConnected) return;
-        mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0;
-        evaluateSubscriptions();
-    }
-
-    @Override
-    public void onSubscribe(Uri conditionId) {
-        if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
-        final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
-        if (downtime == null) return;
-        mFiredAlarms.clear();
-        mSubscriptions.add(conditionId);
-        notifyCondition(downtime);
-    }
-
-    private boolean shouldShowCondition() {
-        final long now = System.currentTimeMillis();
-        if (DEBUG) Slog.d(TAG, "shouldShowCondition now=" + mCalendar.isInDowntime(now)
-                + " lookahead="
-                + (mCalendar.nextDowntimeStart(now) <= (now + mLookaheadThreshold)));
-        return mCalendar.isInDowntime(now)
-                || mCalendar.nextDowntimeStart(now) <= (now + mLookaheadThreshold);
-    }
-
-    private void notifyCondition(DowntimeInfo downtime) {
-        if (mConfig == null) {
-            // we don't know yet
-            notifyCondition(createCondition(downtime, Condition.STATE_UNKNOWN));
-            return;
-        }
-        if (!downtime.equals(mConfig.toDowntimeInfo())) {
-            // not the configured downtime, consider it false
-            notifyCondition(createCondition(downtime, Condition.STATE_FALSE));
-            return;
-        }
-        if (!shouldShowCondition()) {
-            // configured downtime, but not within the time range
-            notifyCondition(createCondition(downtime, Condition.STATE_FALSE));
-            return;
-        }
-        if (isZenNone() && mFiredAlarms.findBefore(System.currentTimeMillis())) {
-            // within the configured time range, but wake up if none and the next alarm is fired
-            notifyCondition(createCondition(downtime, Condition.STATE_FALSE));
-            return;
-        }
-        // within the configured time range, condition still valid
-        notifyCondition(createCondition(downtime, Condition.STATE_TRUE));
-    }
-
-    private boolean isZenNone() {
-        return mZenModeHelper.getZenMode() == Global.ZEN_MODE_NO_INTERRUPTIONS;
-    }
-
-    private boolean isZenOff() {
-        return mZenModeHelper.getZenMode() == Global.ZEN_MODE_OFF;
-    }
-
-    private void evaluateSubscriptions() {
-        ArraySet<Uri> conditions = mSubscriptions;
-        if (mConfig != null && mRequesting && shouldShowCondition()) {
-            final Uri id = ZenModeConfig.toDowntimeConditionId(mConfig.toDowntimeInfo());
-            if (!conditions.contains(id)) {
-                conditions = new ArraySet<Uri>(conditions);
-                conditions.add(id);
-            }
-        }
-        for (Uri conditionId : conditions) {
-            final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
-            if (downtime != null) {
-                notifyCondition(downtime);
-            }
-        }
-    }
-
-    @Override
-    public void onUnsubscribe(Uri conditionId) {
-        final boolean current = mSubscriptions.contains(conditionId);
-        if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId + " current=" + current);
-        mSubscriptions.remove(conditionId);
-        mFiredAlarms.clear();
-    }
-
-    public void setConfig(ZenModeConfig config) {
-        if (Objects.equals(mConfig, config)) return;
-        final boolean downtimeChanged = mConfig == null || config == null
-                || !mConfig.toDowntimeInfo().equals(config.toDowntimeInfo());
-        mConfig = config;
-        if (DEBUG) Slog.d(TAG, "setConfig downtimeChanged=" + downtimeChanged);
-        if (mConnected && downtimeChanged) {
-            mDowntimed = false;
-            init();
-        }
-        // when active, mark downtime as entered for today
-        if (mConfig != null && mConfig.exitCondition != null
-                && ZenModeConfig.isValidDowntimeConditionId(mConfig.exitCondition.id)) {
-            mDowntimed = true;
-        }
-    }
-
-    public void onManualConditionClearing() {
-        mConditionClearing = true;
-    }
-
-    private Condition createCondition(DowntimeInfo downtime, int state) {
-        if (downtime == null) return null;
-        final Uri id = ZenModeConfig.toDowntimeConditionId(downtime);
-        final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma";
-        final Locale locale = Locale.getDefault();
-        final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
-        final long now = System.currentTimeMillis();
-        long endTime = mCalendar.getNextTime(now, downtime.endHour, downtime.endMinute);
-        if (isZenNone()) {
-            final AlarmClockInfo nextAlarm = mTracker.getNextAlarm();
-            final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0;
-            if (nextAlarmTime > now && nextAlarmTime < endTime) {
-                endTime = nextAlarmTime;
-            }
-        }
-        final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(endTime));
-        final String summary = mContext.getString(R.string.downtime_condition_summary, formatted);
-        final String line1 = mContext.getString(R.string.downtime_condition_line_one);
-        return new Condition(id, summary, line1, formatted, 0, state, Condition.FLAG_RELEVANT_NOW);
-    }
-
-    private void init() {
-        mCalendar.setDowntimeInfo(mConfig != null ? mConfig.toDowntimeInfo() : null);
-        evaluateSubscriptions();
-        updateAlarms();
-        evaluateAutotrigger();
-    }
-
-    private void updateAlarms() {
-        if (mConfig == null) return;
-        updateAlarm(ENTER_ACTION, ENTER_CODE, mConfig.sleepStartHour, mConfig.sleepStartMinute);
-        updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute);
-    }
-
-
-    private void updateAlarm(String action, int requestCode, int hr, int min) {
-        final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        final long now = System.currentTimeMillis();
-        final long time = mCalendar.getNextTime(now, hr, min);
-        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
-                new Intent(action)
-                    .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                    .putExtra(EXTRA_TIME, time),
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        alarms.cancel(pendingIntent);
-        if (mConfig.sleepMode != null) {
-            if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, in %s, now=%s",
-                    action, ts(time), NextAlarmTracker.formatDuration(time - now), ts(now)));
-            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
-        }
-    }
-
-    private static String ts(long time) {
-        return new Date(time) + " (" + time + ")";
-    }
-
-    private void onEvaluateNextAlarm(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
-        if (!booted) return;  // we don't know yet
-        if (DEBUG) Slog.d(TAG, "onEvaluateNextAlarm " + mTracker.formatAlarmDebug(nextAlarm));
-        if (nextAlarm != null && wakeupTime > 0 && System.currentTimeMillis() > wakeupTime) {
-            if (DEBUG) Slog.d(TAG, "Alarm fired: " + mTracker.formatAlarmDebug(wakeupTime));
-            mFiredAlarms.add(wakeupTime);
-        }
-        evaluateSubscriptions();
-    }
-
-    private void evaluateAutotrigger() {
-        String skipReason = null;
-        if (mConfig == null) {
-            skipReason = "no config";
-        } else if (mDowntimed) {
-            skipReason = "already downtimed";
-        } else if (mZenModeHelper.getZenMode() != Global.ZEN_MODE_OFF) {
-            skipReason = "already in zen";
-        } else if (!mCalendar.isInDowntime(System.currentTimeMillis())) {
-            skipReason = "not in downtime";
-        }
-        if (skipReason != null) {
-            ZenLog.traceDowntimeAutotrigger("Autotrigger skipped: " + skipReason);
-            return;
-        }
-        ZenLog.traceDowntimeAutotrigger("Autotrigger fired");
-        mZenModeHelper.setZenMode(mConfig.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
-                : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtime");
-        final Condition condition = createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE);
-        mConditionProviders.setZenModeCondition(condition, "downtime");
-    }
-
-    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            final long now = System.currentTimeMillis();
-            if (ENTER_ACTION.equals(action) || EXIT_ACTION.equals(action)) {
-                final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
-                if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
-                        action, ts(schTime), ts(now), now - schTime));
-                if (ENTER_ACTION.equals(action)) {
-                    evaluateAutotrigger();
-                } else /*EXIT_ACTION*/ {
-                    mDowntimed = false;
-                }
-                mFiredAlarms.clear();
-            } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
-                if (DEBUG) Slog.d(TAG, "timezone changed to " + TimeZone.getDefault());
-                mCalendar.setTimeZone(TimeZone.getDefault());
-                mFiredAlarms.clear();
-            } else if (Intent.ACTION_TIME_CHANGED.equals(action)) {
-                if (DEBUG) Slog.d(TAG, "time changed to " + now);
-                mFiredAlarms.clear();
-            } else {
-                if (DEBUG) Slog.d(TAG, action + " fired at " + now);
-            }
-            evaluateSubscriptions();
-            updateAlarms();
-        }
-    };
-
-    private final NextAlarmTracker.Callback mTrackerCallback = new NextAlarmTracker.Callback() {
-        @Override
-        public void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
-            DowntimeConditionProvider.this.onEvaluateNextAlarm(nextAlarm, wakeupTime, booted);
-        }
-    };
-
-    private final ZenModeHelper.Callback mZenCallback = new ZenModeHelper.Callback() {
-        @Override
-        void onZenModeChanged() {
-            if (mConditionClearing && isZenOff()) {
-                evaluateAutotrigger();
-            }
-            mConditionClearing = false;
-            evaluateSubscriptions();
-        }
-    };
-
-    private class FiredAlarms {
-        private final ArraySet<Long> mFiredAlarms = new ArraySet<Long>();
-
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < mFiredAlarms.size(); i++) {
-                if (i > 0) sb.append(',');
-                sb.append(mTracker.formatAlarmDebug(mFiredAlarms.valueAt(i)));
-            }
-            return sb.toString();
-        }
-
-        public void add(long firedAlarm) {
-            mFiredAlarms.add(firedAlarm);
-        }
-
-        public void clear() {
-            mFiredAlarms.clear();
-        }
-
-        public boolean findBefore(long time) {
-            for (int i = 0; i < mFiredAlarms.size(); i++) {
-                if (mFiredAlarms.valueAt(i) < time) {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java b/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java
deleted file mode 100644
index 1634c65..0000000
--- a/services/core/java/com/android/server/notification/NextAlarmConditionProvider.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.notification;
-
-import android.app.AlarmManager;
-import android.app.AlarmManager.AlarmClockInfo;
-import android.content.ComponentName;
-import android.content.Context;
-import android.net.Uri;
-import android.service.notification.Condition;
-import android.service.notification.ConditionProviderService;
-import android.service.notification.IConditionProvider;
-import android.service.notification.ZenModeConfig;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.TimeUtils;
-
-import com.android.internal.R;
-import com.android.server.notification.NotificationManagerService.DumpFilter;
-
-import java.io.PrintWriter;
-
-/**
- * Built-in zen condition provider for alarm-clock-based conditions.
- *
- * <p>If the user's next alarm is within a lookahead threshold (config, default 12hrs), advertise
- * it as an exit condition for zen mode.
- *
- * <p>The next alarm is defined as {@link AlarmManager#getNextAlarmClock(int)}, which does not
- * survive a reboot.  Maintain the illusion of a consistent next alarm value by holding on to
- * a persisted condition until we receive the first value after reboot, or timeout with no value.
- */
-public class NextAlarmConditionProvider extends ConditionProviderService {
-    private static final String TAG = "NextAlarmConditions";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final long SECONDS = 1000;
-    private static final long MINUTES = 60 * SECONDS;
-    private static final long HOURS = 60 * MINUTES;
-
-    private static final long BAD_CONDITION = -1;
-
-    public static final ComponentName COMPONENT =
-            new ComponentName("android", NextAlarmConditionProvider.class.getName());
-
-    private final Context mContext = this;
-    private final NextAlarmTracker mTracker;
-    private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
-
-    private boolean mConnected;
-    private long mLookaheadThreshold;
-    private boolean mRequesting;
-
-    public NextAlarmConditionProvider(NextAlarmTracker tracker) {
-        if (DEBUG) Slog.d(TAG, "new NextAlarmConditionProvider()");
-        mTracker = tracker;
-    }
-
-    public void dump(PrintWriter pw, DumpFilter filter) {
-        pw.println("    NextAlarmConditionProvider:");
-        pw.print("      mConnected="); pw.println(mConnected);
-        pw.print("      mLookaheadThreshold="); pw.print(mLookaheadThreshold);
-        pw.print(" ("); TimeUtils.formatDuration(mLookaheadThreshold, pw); pw.println(")");
-        pw.print("      mSubscriptions="); pw.println(mSubscriptions);
-        pw.print("      mRequesting="); pw.println(mRequesting);
-    }
-
-    @Override
-    public void onConnected() {
-        if (DEBUG) Slog.d(TAG, "onConnected");
-        mLookaheadThreshold = PropConfig.getInt(mContext, "nextalarm.condition.lookahead",
-                R.integer.config_next_alarm_condition_lookahead_threshold_hrs) * HOURS;
-        mConnected = true;
-        mTracker.addCallback(mTrackerCallback);
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        if (DEBUG) Slog.d(TAG, "onDestroy");
-        mTracker.removeCallback(mTrackerCallback);
-        mConnected = false;
-    }
-
-    @Override
-    public void onRequestConditions(int relevance) {
-        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
-        if (!mConnected) return;
-        mRequesting = (relevance & Condition.FLAG_RELEVANT_NOW) != 0;
-        mTracker.evaluate();
-    }
-
-    @Override
-    public void onSubscribe(Uri conditionId) {
-        if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
-        if (tryParseNextAlarmCondition(conditionId) == BAD_CONDITION) {
-            notifyCondition(conditionId, null, Condition.STATE_FALSE, "badCondition");
-            return;
-        }
-        mSubscriptions.add(conditionId);
-        mTracker.evaluate();
-    }
-
-    @Override
-    public void onUnsubscribe(Uri conditionId) {
-        if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
-        mSubscriptions.remove(conditionId);
-    }
-
-    public void attachBase(Context base) {
-        attachBaseContext(base);
-    }
-
-    public IConditionProvider asInterface() {
-        return (IConditionProvider) onBind(null);
-    }
-
-    private boolean isWithinLookaheadThreshold(AlarmClockInfo alarm) {
-        if (alarm == null) return false;
-        final long delta = NextAlarmTracker.getEarlyTriggerTime(alarm) - System.currentTimeMillis();
-        return delta > 0 && (mLookaheadThreshold <= 0 || delta < mLookaheadThreshold);
-    }
-
-    private void notifyCondition(Uri id, AlarmClockInfo alarm, int state, String reason) {
-        final String formattedAlarm = alarm == null ? "" : mTracker.formatAlarm(alarm);
-        if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state)
-                + " alarm=" + formattedAlarm + " reason=" + reason);
-        notifyCondition(new Condition(id,
-                mContext.getString(R.string.zen_mode_next_alarm_summary, formattedAlarm),
-                mContext.getString(R.string.zen_mode_next_alarm_line_one),
-                formattedAlarm, 0, state, Condition.FLAG_RELEVANT_NOW));
-    }
-
-    private Uri newConditionId(AlarmClockInfo nextAlarm) {
-        return new Uri.Builder().scheme(Condition.SCHEME)
-                .authority(ZenModeConfig.SYSTEM_AUTHORITY)
-                .appendPath(ZenModeConfig.NEXT_ALARM_PATH)
-                .appendPath(Integer.toString(mTracker.getCurrentUserId()))
-                .appendPath(Long.toString(nextAlarm.getTriggerTime()))
-                .build();
-    }
-
-    private long tryParseNextAlarmCondition(Uri conditionId) {
-        return conditionId != null && conditionId.getScheme().equals(Condition.SCHEME)
-                && conditionId.getAuthority().equals(ZenModeConfig.SYSTEM_AUTHORITY)
-                && conditionId.getPathSegments().size() == 3
-                && conditionId.getPathSegments().get(0).equals(ZenModeConfig.NEXT_ALARM_PATH)
-                && conditionId.getPathSegments().get(1)
-                        .equals(Integer.toString(mTracker.getCurrentUserId()))
-                                ? tryParseLong(conditionId.getPathSegments().get(2), BAD_CONDITION)
-                                : BAD_CONDITION;
-    }
-
-    private static long tryParseLong(String value, long defValue) {
-        if (TextUtils.isEmpty(value)) return defValue;
-        try {
-            return Long.valueOf(value);
-        } catch (NumberFormatException e) {
-            return defValue;
-        }
-    }
-
-    private void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
-        final boolean withinThreshold = isWithinLookaheadThreshold(nextAlarm);
-        final long nextAlarmTime = nextAlarm != null ? nextAlarm.getTriggerTime() : 0;
-        if (DEBUG) Slog.d(TAG, "onEvaluate mSubscriptions=" + mSubscriptions
-                + " nextAlarmTime=" +  mTracker.formatAlarmDebug(nextAlarmTime)
-                + " nextAlarmWakeup=" + mTracker.formatAlarmDebug(wakeupTime)
-                + " withinThreshold=" + withinThreshold
-                + " booted=" + booted);
-
-        ArraySet<Uri> conditions = mSubscriptions;
-        if (mRequesting && nextAlarm != null && withinThreshold) {
-            final Uri id = newConditionId(nextAlarm);
-            if (!conditions.contains(id)) {
-                conditions = new ArraySet<Uri>(conditions);
-                conditions.add(id);
-            }
-        }
-        for (Uri conditionId : conditions) {
-            final long time = tryParseNextAlarmCondition(conditionId);
-            if (time == BAD_CONDITION) {
-                notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "badCondition");
-            } else if (!booted) {
-                // we don't know yet
-                if (mSubscriptions.contains(conditionId)) {
-                    notifyCondition(conditionId, nextAlarm, Condition.STATE_UNKNOWN, "!booted");
-                }
-            } else if (time != nextAlarmTime) {
-                // next alarm changed since subscription, consider obsolete
-                notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "changed");
-            } else if (!withinThreshold) {
-                // next alarm outside threshold or in the past, condition = false
-                notifyCondition(conditionId, nextAlarm, Condition.STATE_FALSE, "!within");
-            } else {
-                // next alarm within threshold and in the future, condition = true
-                notifyCondition(conditionId, nextAlarm, Condition.STATE_TRUE, "within");
-            }
-        }
-    }
-
-    private final NextAlarmTracker.Callback mTrackerCallback = new NextAlarmTracker.Callback() {
-        @Override
-        public void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
-            NextAlarmConditionProvider.this.onEvaluate(nextAlarm, wakeupTime, booted);
-        }
-    };
-}
diff --git a/services/core/java/com/android/server/notification/NextAlarmTracker.java b/services/core/java/com/android/server/notification/NextAlarmTracker.java
deleted file mode 100644
index 234f545..0000000
--- a/services/core/java/com/android/server/notification/NextAlarmTracker.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.notification;
-
-import android.app.ActivityManager;
-import android.app.AlarmManager;
-import android.app.AlarmManager.AlarmClockInfo;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.UserHandle;
-import android.text.format.DateFormat;
-import android.util.Log;
-import android.util.Slog;
-import android.util.TimeUtils;
-
-import com.android.server.notification.NotificationManagerService.DumpFilter;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Locale;
-
-/** Helper for tracking updates to the current user's next alarm. */
-public class NextAlarmTracker {
-    private static final String TAG = "NextAlarmTracker";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-    private static final String ACTION_TRIGGER = TAG + ".trigger";
-    private static final String EXTRA_TRIGGER = "trigger";
-    private static final int REQUEST_CODE = 100;
-
-    private static final long SECONDS = 1000;
-    private static final long MINUTES = 60 * SECONDS;
-    private static final long NEXT_ALARM_UPDATE_DELAY = 1 * SECONDS;  // treat clear+set as update
-    private static final long EARLY = 5 * SECONDS;  // fire early, ensure alarm stream is unmuted
-    private static final long WAIT_AFTER_INIT = 5 * MINUTES;// for initial alarm re-registration
-    private static final long WAIT_AFTER_BOOT = 20 * SECONDS;  // for initial alarm re-registration
-
-    private final Context mContext;
-    private final H mHandler = new H();
-    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
-
-    private long mInit;
-    private boolean mRegistered;
-    private AlarmManager mAlarmManager;
-    private int mCurrentUserId;
-    private long mScheduledAlarmTime;
-    private long mBootCompleted;
-    private PowerManager.WakeLock mWakeLock;
-
-    public NextAlarmTracker(Context context) {
-        mContext = context;
-    }
-
-    public void dump(PrintWriter pw, DumpFilter filter) {
-        pw.println("    NextAlarmTracker:");
-        pw.print("      len(mCallbacks)="); pw.println(mCallbacks.size());
-        pw.print("      mRegistered="); pw.println(mRegistered);
-        pw.print("      mInit="); pw.println(mInit);
-        pw.print("      mBootCompleted="); pw.println(mBootCompleted);
-        pw.print("      mCurrentUserId="); pw.println(mCurrentUserId);
-        pw.print("      mScheduledAlarmTime="); pw.println(formatAlarmDebug(mScheduledAlarmTime));
-        pw.print("      mWakeLock="); pw.println(mWakeLock);
-    }
-
-    public void addCallback(Callback callback) {
-        mCallbacks.add(callback);
-    }
-
-    public void removeCallback(Callback callback) {
-        mCallbacks.remove(callback);
-    }
-
-    public int getCurrentUserId() {
-        return mCurrentUserId;
-    }
-
-    public AlarmClockInfo getNextAlarm() {
-        return mAlarmManager.getNextAlarmClock(mCurrentUserId);
-    }
-
-    public void onUserSwitched() {
-        reset();
-    }
-
-    public void init() {
-        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        final PowerManager p = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = p.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
-        mInit = System.currentTimeMillis();
-        reset();
-    }
-
-    public void reset() {
-        if (mRegistered) {
-            mContext.unregisterReceiver(mReceiver);
-        }
-        mCurrentUserId = ActivityManager.getCurrentUser();
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
-        filter.addAction(ACTION_TRIGGER);
-        filter.addAction(Intent.ACTION_TIME_CHANGED);
-        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
-        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        mContext.registerReceiverAsUser(mReceiver, new UserHandle(mCurrentUserId), filter, null,
-                null);
-        mRegistered = true;
-        evaluate();
-    }
-
-    public void destroy() {
-        if (mRegistered) {
-            mContext.unregisterReceiver(mReceiver);
-            mRegistered = false;
-        }
-    }
-
-    public void evaluate() {
-        mHandler.postEvaluate(0);
-    }
-
-    private void fireEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted) {
-        for (Callback callback : mCallbacks) {
-            callback.onEvaluate(nextAlarm, wakeupTime, booted);
-        }
-    }
-
-    private void handleEvaluate() {
-        final AlarmClockInfo nextAlarm = mAlarmManager.getNextAlarmClock(mCurrentUserId);
-        final long triggerTime = getEarlyTriggerTime(nextAlarm);
-        final long now = System.currentTimeMillis();
-        final boolean alarmUpcoming = triggerTime > now;
-        final boolean booted = isDoneWaitingAfterBoot(now);
-        if (DEBUG) Slog.d(TAG, "handleEvaluate nextAlarm=" + formatAlarmDebug(triggerTime)
-                + " alarmUpcoming=" + alarmUpcoming
-                + " booted=" + booted);
-        fireEvaluate(nextAlarm, triggerTime, booted);
-        if (!booted) {
-            // recheck after boot
-            final long recheckTime = (mBootCompleted > 0 ? mBootCompleted : now) + WAIT_AFTER_BOOT;
-            rescheduleAlarm(recheckTime);
-            return;
-        }
-        if (alarmUpcoming) {
-            // wake up just before the next alarm
-            rescheduleAlarm(triggerTime);
-        }
-    }
-
-    public static long getEarlyTriggerTime(AlarmClockInfo alarm) {
-        return alarm != null ? (alarm.getTriggerTime() - EARLY) : 0;
-    }
-
-    private boolean isDoneWaitingAfterBoot(long time) {
-        if (mBootCompleted > 0) return (time - mBootCompleted) > WAIT_AFTER_BOOT;
-        if (mInit > 0) return (time - mInit) > WAIT_AFTER_INIT;
-        return true;
-    }
-
-    public static String formatDuration(long millis) {
-        final StringBuilder sb = new StringBuilder();
-        TimeUtils.formatDuration(millis, sb);
-        return sb.toString();
-    }
-
-    public String formatAlarm(AlarmClockInfo alarm) {
-        return alarm != null ? formatAlarm(alarm.getTriggerTime()) : null;
-    }
-
-    private String formatAlarm(long time) {
-        return formatAlarm(time, "Hm", "hma");
-    }
-
-    private String formatAlarm(long time, String skeleton24, String skeleton12) {
-        final String skeleton = DateFormat.is24HourFormat(mContext) ? skeleton24 : skeleton12;
-        final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
-        return DateFormat.format(pattern, time).toString();
-    }
-
-    public String formatAlarmDebug(AlarmClockInfo alarm) {
-        return formatAlarmDebug(alarm != null ? alarm.getTriggerTime() : 0);
-    }
-
-    public String formatAlarmDebug(long time) {
-        if (time <= 0) return Long.toString(time);
-        return String.format("%s (%s)", time, formatAlarm(time, "Hms", "hmsa"));
-    }
-
-    private void rescheduleAlarm(long time) {
-        if (DEBUG) Slog.d(TAG, "rescheduleAlarm " + time);
-        final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
-        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
-                new Intent(ACTION_TRIGGER)
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .putExtra(EXTRA_TRIGGER, time),
-                PendingIntent.FLAG_UPDATE_CURRENT);
-        alarms.cancel(pendingIntent);
-        mScheduledAlarmTime = time;
-        if (time > 0) {
-            if (DEBUG) Slog.d(TAG, String.format("Scheduling alarm for %s (in %s)",
-                    formatAlarmDebug(time), formatDuration(time - System.currentTimeMillis())));
-            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
-        }
-    }
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (DEBUG) Slog.d(TAG, "onReceive " + action);
-            long delay = 0;
-            if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
-                delay = NEXT_ALARM_UPDATE_DELAY;
-                if (DEBUG) Slog.d(TAG, String.format("  next alarm for user %s: %s",
-                        mCurrentUserId,
-                        formatAlarmDebug(mAlarmManager.getNextAlarmClock(mCurrentUserId))));
-            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
-                mBootCompleted = System.currentTimeMillis();
-            }
-            mHandler.postEvaluate(delay);
-            mWakeLock.acquire(delay + 5000);  // stay awake during evaluate
-        }
-    };
-
-    private class H extends Handler {
-        private static final int MSG_EVALUATE = 1;
-
-        public void postEvaluate(long delay) {
-            removeMessages(MSG_EVALUATE);
-            sendEmptyMessageDelayed(MSG_EVALUATE, delay);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == MSG_EVALUATE) {
-                handleEvaluate();
-            }
-        }
-    }
-
-    public interface Callback {
-        void onEvaluate(AlarmClockInfo nextAlarm, long wakeupTime, boolean booted);
-    }
-}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c330046..4cf2909 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -879,7 +879,8 @@
         mRankingHelper = new RankingHelper(getContext(),
                 new RankingWorkerHandler(mRankingThread.getLooper()),
                 extractorNames);
-        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper());
+        mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
+        mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders);
         mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
             @Override
             public void onConfigChanged() {
@@ -900,8 +901,6 @@
         importOldBlockDb();
 
         mListeners = new NotificationListeners();
-        mConditionProviders = new ConditionProviders(getContext(),
-                mHandler, mUserProfiles, mZenModeHelper);
         mStatusBar = getLocalService(StatusBarManagerInternal.class);
         mStatusBar.setNotificationDelegate(mNotificationDelegate);
 
@@ -936,7 +935,7 @@
                     Settings.Global.DEVICE_PROVISIONED, 0)) {
             mDisableNotificationEffects = true;
         }
-        mZenModeHelper.readZenModeFromSetting();
+        mZenModeHelper.initZenMode();
         mInterruptionFilter = mZenModeHelper.getZenModeListenerInterruptionFilter();
 
         mUserProfiles.updateCache(getContext());
@@ -1490,23 +1489,28 @@
         }
 
         @Override
+        public int getZenMode() {
+            return mZenModeHelper.getZenMode();
+        }
+
+        @Override
         public ZenModeConfig getZenModeConfig() {
             enforceSystemOrSystemUIOrVolume("INotificationManager.getZenModeConfig");
             return mZenModeHelper.getConfig();
         }
 
         @Override
-        public boolean setZenModeConfig(ZenModeConfig config) {
+        public boolean setZenModeConfig(ZenModeConfig config, String reason) {
             checkCallerIsSystem();
-            return mZenModeHelper.setConfig(config);
+            return mZenModeHelper.setConfig(config, reason);
         }
 
         @Override
-        public void setZenMode(int mode) throws RemoteException {
+        public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
             enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
             final long identity = Binder.clearCallingIdentity();
             try {
-                mZenModeHelper.setZenMode(mode, "NotificationManager");
+                mZenModeHelper.setManualZenMode(mode, conditionId, reason);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -1528,30 +1532,7 @@
         @Override
         public void requestZenModeConditions(IConditionListener callback, int relevance) {
             enforceSystemOrSystemUIOrVolume("INotificationManager.requestZenModeConditions");
-            mConditionProviders.requestZenModeConditions(callback, relevance);
-        }
-
-        @Override
-        public void setZenModeCondition(Condition condition) {
-            enforceSystemOrSystemUIOrVolume("INotificationManager.setZenModeCondition");
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                mConditionProviders.setZenModeCondition(condition, "binderCall");
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        @Override
-        public void setAutomaticZenModeConditions(Uri[] conditionIds) {
-            enforceSystemOrSystemUI("INotificationManager.setAutomaticZenModeConditions");
-            mConditionProviders.setAutomaticZenModeConditions(conditionIds);
-        }
-
-        @Override
-        public Condition[] getAutomaticZenModeConditions() {
-            enforceSystemOrSystemUI("INotificationManager.getAutomaticZenModeConditions");
-            return mConditionProviders.getAutomaticZenModeConditions();
+            mZenModeHelper.requestZenModeConditions(callback, relevance);
         }
 
         private void enforceSystemOrSystemUIOrVolume(String message) {
@@ -1603,7 +1584,7 @@
         @Override
         public boolean isSystemConditionProviderEnabled(String path) {
             enforceSystemOrSystemUIOrVolume("INotificationManager.isSystemConditionProviderEnabled");
-            return mConditionProviders.isSystemConditionProviderEnabled(path);
+            return mConditionProviders.isSystemProviderEnabled(path);
         }
     };
 
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index e029c58..4696771 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -28,6 +28,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.server.notification.NotificationManagerService.DumpFilter;
 
 import java.io.PrintWriter;
@@ -56,8 +57,10 @@
     // Guarded by synchronized(this).
     private final Map<String, AggregatedStats> mStats = new HashMap<String, AggregatedStats>();
     private final SQLiteLog mSQLiteLog;
+    private final Context mContext;
 
     public NotificationUsageStats(Context context) {
+        mContext = context;
         mSQLiteLog = ENABLE_SQLITE_LOG ? new SQLiteLog(context) : null;
     }
 
@@ -103,6 +106,8 @@
      * Called when the user dismissed the notification via the UI.
      */
     public synchronized void registerDismissedByUser(NotificationRecord notification) {
+        MetricsLogger.histogram(mContext, "note_dismiss_longevity",
+                (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
         notification.stats.onDismiss();
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numDismissedByUser++;
@@ -117,6 +122,8 @@
      * Called when the user clicked the notification in the UI.
      */
     public synchronized void registerClickedByUser(NotificationRecord notification) {
+        MetricsLogger.histogram(mContext, "note_click_longevity",
+                (int) (System.currentTimeMillis() - notification.getRankingTimeMs()) / (60 * 1000));
         notification.stats.onClick();
         for (AggregatedStats stats : getAggregatedStatsLocked(notification)) {
             stats.numClickedByUser++;
diff --git a/services/core/java/com/android/server/notification/DowntimeCalendar.java b/services/core/java/com/android/server/notification/ScheduleCalendar.java
similarity index 62%
rename from services/core/java/com/android/server/notification/DowntimeCalendar.java
rename to services/core/java/com/android/server/notification/ScheduleCalendar.java
index d14fd40..cea611d 100644
--- a/services/core/java/com/android/server/notification/DowntimeCalendar.java
+++ b/services/core/java/com/android/server/notification/ScheduleCalendar.java
@@ -16,38 +16,36 @@
 
 package com.android.server.notification;
 
+import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.util.ArraySet;
+
 import java.util.Calendar;
 import java.util.Objects;
 import java.util.TimeZone;
 
-import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.DowntimeInfo;
-import android.util.ArraySet;
-
-public class DowntimeCalendar {
-
+public class ScheduleCalendar {
     private final ArraySet<Integer> mDays = new ArraySet<Integer>();
     private final Calendar mCalendar = Calendar.getInstance();
 
-    private DowntimeInfo mInfo;
+    private ScheduleInfo mSchedule;
 
     @Override
     public String toString() {
-        return "DowntimeCalendar[mDays=" + mDays + "]";
+        return "ScheduleCalendar[mDays=" + mDays + "]";
     }
 
-    public void setDowntimeInfo(DowntimeInfo info) {
-        if (Objects.equals(mInfo, info)) return;
-        mInfo = info;
+    public void setSchedule(ScheduleInfo schedule) {
+        if (Objects.equals(mSchedule, schedule)) return;
+        mSchedule = schedule;
         updateDays();
     }
 
-    public long nextDowntimeStart(long time) {
-        if (mInfo == null || mDays.size() == 0) return Long.MAX_VALUE;
-        final long start = getTime(time, mInfo.startHour, mInfo.startMinute);
+    public long nextScheduleStart(long time) {
+        if (mSchedule == null || mDays.size() == 0) return Long.MAX_VALUE;
+        final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
         for (int i = 0; i < Calendar.SATURDAY; i++) {
             final long t = addDays(start, i);
-            if (t > time && isInDowntime(t)) {
+            if (t > time && isInSchedule(t)) {
                 return t;
             }
         }
@@ -58,7 +56,14 @@
         mCalendar.setTimeZone(tz);
     }
 
-    public long getNextTime(long now, int hr, int min) {
+    public long getNextChangeTime(long now) {
+        if (mSchedule == null) return 0;
+        final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
+        final long nextEnd = getNextTime(now, mSchedule.endHour, mSchedule.endMinute);
+        return Math.min(nextStart, nextEnd);
+    }
+
+    private long getNextTime(long now, int hr, int min) {
         final long time = getTime(now, hr, min);
         return time <= now ? addDays(time, 1) : time;
     }
@@ -72,17 +77,17 @@
         return mCalendar.getTimeInMillis();
     }
 
-    public boolean isInDowntime(long time) {
-        if (mInfo == null || mDays.size() == 0) return false;
-        final long start = getTime(time, mInfo.startHour, mInfo.startMinute);
-        long end = getTime(time, mInfo.endHour, mInfo.endMinute);
+    public boolean isInSchedule(long time) {
+        if (mSchedule == null || mDays.size() == 0) return false;
+        final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
+        long end = getTime(time, mSchedule.endHour, mSchedule.endMinute);
         if (end <= start) {
             end = addDays(end, 1);
         }
-        return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end);
+        return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
     }
 
-    private boolean isInDowntime(int daysOffset, long time, long start, long end) {
+    private boolean isInSchedule(int daysOffset, long time, long start, long end) {
         final int n = Calendar.SATURDAY;
         final int day = ((getDayOfWeek(time) - 1) + (daysOffset % n) + n) % n + 1;
         start = addDays(start, daysOffset);
@@ -97,10 +102,9 @@
 
     private void updateDays() {
         mDays.clear();
-        if (mInfo != null) {
-            final int[] days = ZenModeConfig.tryParseDays(mInfo.mode);
-            for (int i = 0; days != null && i < days.length; i++) {
-                mDays.add(days[i]);
+        if (mSchedule != null && mSchedule.days != null) {
+            for (int i = 0; i < mSchedule.days.length; i++) {
+                mDays.add(mSchedule.days[i]);
             }
         }
     }
@@ -110,4 +114,4 @@
         mCalendar.add(Calendar.DATE, days);
         return mCalendar.getTimeInMillis();
     }
-}
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
new file mode 100644
index 0000000..c997e45
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+import android.util.TimeUtils;
+
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Built-in zen condition provider for daily scheduled time-based conditions.
+ */
+public class ScheduleConditionProvider extends SystemConditionProviderService {
+    private static final String TAG = "ScheduleConditions";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    public static final ComponentName COMPONENT =
+            new ComponentName("android", ScheduleConditionProvider.class.getName());
+    private static final String NOT_SHOWN = "...";
+    private static final String ACTION_EVALUATE = TAG + ".EVALUATE";
+    private static final int REQUEST_CODE_EVALUATE = 1;
+    private static final String EXTRA_TIME = "time";
+
+    private final Context mContext = this;
+    private final ArraySet<Uri> mSubscriptions = new ArraySet<Uri>();
+
+    private boolean mConnected;
+    private boolean mRegistered;
+
+    public ScheduleConditionProvider() {
+        if (DEBUG) Slog.d(TAG, "new ScheduleConditionProvider()");
+    }
+
+    @Override
+    public ComponentName getComponent() {
+        return COMPONENT;
+    }
+
+    @Override
+    public boolean isValidConditionid(Uri id) {
+        return ZenModeConfig.isValidScheduleConditionId(id);
+    }
+
+    @Override
+    public void dump(PrintWriter pw, DumpFilter filter) {
+        pw.println("    ScheduleConditionProvider:");
+        pw.print("      mConnected="); pw.println(mConnected);
+        pw.print("      mRegistered="); pw.println(mRegistered);
+        pw.println("      mSubscriptions=");
+        final long now = System.currentTimeMillis();
+        for (Uri conditionId : mSubscriptions) {
+            pw.print("        ");
+            pw.print(meetsSchedule(conditionId, now) ? "* " : "  ");
+            pw.println(conditionId);
+        }
+    }
+
+    @Override
+    public void onConnected() {
+        if (DEBUG) Slog.d(TAG, "onConnected");
+        mConnected = true;
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (DEBUG) Slog.d(TAG, "onDestroy");
+        mConnected = false;
+    }
+
+    @Override
+    public void onRequestConditions(int relevance) {
+        if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
+        // does not advertise conditions
+    }
+
+    @Override
+    public void onSubscribe(Uri conditionId) {
+        if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
+        if (!ZenModeConfig.isValidScheduleConditionId(conditionId)) {
+            notifyCondition(conditionId, Condition.STATE_FALSE, "badCondition");
+            return;
+        }
+        mSubscriptions.add(conditionId);
+        evaluateSubscriptions();
+    }
+
+    @Override
+    public void onUnsubscribe(Uri conditionId) {
+        if (DEBUG) Slog.d(TAG, "onUnsubscribe " + conditionId);
+        mSubscriptions.remove(conditionId);
+        evaluateSubscriptions();
+    }
+
+    @Override
+    public void attachBase(Context base) {
+        attachBaseContext(base);
+    }
+
+    @Override
+    public IConditionProvider asInterface() {
+        return (IConditionProvider) onBind(null);
+    }
+
+    private void evaluateSubscriptions() {
+        setRegistered(!mSubscriptions.isEmpty());
+        final long now = System.currentTimeMillis();
+        long nextAlarmTime = 0;
+        for (Uri conditionId : mSubscriptions) {
+            final ScheduleCalendar cal = toScheduleCalendar(conditionId);
+            if (cal != null && cal.isInSchedule(now)) {
+                notifyCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
+            } else {
+                notifyCondition(conditionId, Condition.STATE_FALSE, "!meetsSchedule");
+            }
+            if (cal != null) {
+                final long nextChangeTime = cal.getNextChangeTime(now);
+                if (nextChangeTime > 0 && nextChangeTime > now) {
+                    if (nextAlarmTime == 0 || nextChangeTime < nextAlarmTime) {
+                        nextAlarmTime = nextChangeTime;
+                    }
+                }
+            }
+        }
+        updateAlarm(now, nextAlarmTime);
+    }
+
+    private void updateAlarm(long now, long time) {
+        final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext,
+                REQUEST_CODE_EVALUATE,
+                new Intent(ACTION_EVALUATE)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                        .putExtra(EXTRA_TIME, time),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        alarms.cancel(pendingIntent);
+        if (time > now) {
+            if (DEBUG) Slog.d(TAG, String.format("Scheduling evaluate for %s, in %s, now=%s",
+                    ts(time), formatDuration(time - now), ts(now)));
+            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+        } else {
+            if (DEBUG) Slog.d(TAG, "Not scheduling evaluate");
+        }
+    }
+
+    private static String ts(long time) {
+        return new Date(time) + " (" + time + ")";
+    }
+
+    private static String formatDuration(long millis) {
+        final StringBuilder sb = new StringBuilder();
+        TimeUtils.formatDuration(millis, sb);
+        return sb.toString();
+    }
+
+    private static boolean meetsSchedule(Uri conditionId, long time) {
+        final ScheduleCalendar cal = toScheduleCalendar(conditionId);
+        return cal != null && cal.isInSchedule(time);
+    }
+
+    private static ScheduleCalendar toScheduleCalendar(Uri conditionId) {
+        final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(conditionId);
+        if (schedule == null || schedule.days == null || schedule.days.length == 0) return null;
+        final ScheduleCalendar sc = new ScheduleCalendar();
+        sc.setSchedule(schedule);
+        sc.setTimeZone(TimeZone.getDefault());
+        return sc;
+    }
+
+    private void setRegistered(boolean registered) {
+        if (mRegistered == registered) return;
+        if (DEBUG) Slog.d(TAG, "setRegistered " + registered);
+        mRegistered = registered;
+        if (mRegistered) {
+            final IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_TIME_CHANGED);
+            filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+            filter.addAction(ACTION_EVALUATE);
+            registerReceiver(mReceiver, filter);
+        } else {
+            unregisterReceiver(mReceiver);
+        }
+    }
+
+    private void notifyCondition(Uri conditionId, int state, String reason) {
+        if (DEBUG) Slog.d(TAG, "notifyCondition " + Condition.stateToString(state)
+                + " reason=" + reason);
+        notifyCondition(createCondition(conditionId, state));
+    }
+
+    private Condition createCondition(Uri id, int state) {
+        final String summary = NOT_SHOWN;
+        final String line1 = NOT_SHOWN;
+        final String line2 = NOT_SHOWN;
+        return new Condition(id, summary, line1, line2, 0, state, Condition.FLAG_RELEVANT_ALWAYS);
+    }
+
+    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) Slog.d(TAG, "onReceive " + intent.getAction());
+            evaluateSubscriptions();
+        }
+    };
+
+}
diff --git a/services/core/java/com/android/server/notification/SystemConditionProviderService.java b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
new file mode 100644
index 0000000..a217623
--- /dev/null
+++ b/services/core/java/com/android/server/notification/SystemConditionProviderService.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.Uri;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionProvider;
+
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+
+public abstract class SystemConditionProviderService extends ConditionProviderService {
+
+    abstract public void dump(PrintWriter pw, DumpFilter filter);
+    abstract public void attachBase(Context context);
+    abstract public IConditionProvider asInterface();
+    abstract public ComponentName getComponent();
+    abstract public boolean isValidConditionid(Uri id);
+}
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index 5eb318b..10f1696 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -34,6 +34,7 @@
 import android.util.Log;
 import android.util.LruCache;
 import android.util.Slog;
+import com.android.internal.logging.MetricsLogger;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
@@ -244,6 +245,7 @@
 
         if (pendingLookups.isEmpty()) {
             if (INFO) Slog.i(TAG, "final affinity: " + affinity);
+            if (affinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1);
             return null;
         }
 
@@ -453,6 +455,8 @@
                 Slog.d(TAG, "Validation finished in " + (System.currentTimeMillis() - timeStartMs) +
                         "ms");
             }
+
+            if (mContactAffinity != NONE) MetricsLogger.count(mBaseContext, "note_with_people", 1);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index 1fc967f..1e318ef 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -172,6 +172,7 @@
         switch (zenMode) {
             case Global.ZEN_MODE_OFF: return "off";
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return "important_interruptions";
+            case Global.ZEN_MODE_ALARMS: return "alarms";
             case Global.ZEN_MODE_NO_INTERRUPTIONS: return "no_interruptions";
             default: return "unknown";
         }
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
new file mode 100644
index 0000000..67a2a54
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.ZenRule;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.io.PrintWriter;
+import java.util.Objects;
+
+public class ZenModeConditions implements ConditionProviders.Callback {
+    private static final String TAG = ZenModeHelper.TAG;
+    private static final boolean DEBUG = ZenModeHelper.DEBUG;
+
+    private final ZenModeHelper mHelper;
+    private final ConditionProviders mConditionProviders;
+    private final ArrayMap<Uri, ComponentName> mSubscriptions = new ArrayMap<>();
+
+    private CountdownConditionProvider mCountdown;
+    private ScheduleConditionProvider mSchedule;
+
+    public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
+        mHelper = helper;
+        mConditionProviders = conditionProviders;
+        if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.COUNTDOWN_PATH)) {
+            mCountdown = new CountdownConditionProvider();
+            mConditionProviders.addSystemProvider(mCountdown);
+        }
+        if (mConditionProviders.isSystemProviderEnabled(ZenModeConfig.SCHEDULE_PATH)) {
+            mSchedule = new ScheduleConditionProvider();
+            mConditionProviders.addSystemProvider(mSchedule);
+        }
+        mConditionProviders.setCallback(this);
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mSubscriptions="); pw.println(mSubscriptions);
+    }
+
+    public void requestConditions(IConditionListener callback, int relevance) {
+        mConditionProviders.requestConditions(callback, relevance);
+    }
+
+    public void evaluateConfig(ZenModeConfig config) {
+        if (config == null) return;
+        if (config.manualRule != null && !config.manualRule.isTrueOrUnknown()) {
+            if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule");
+            config.manualRule = null;
+        }
+        final ArraySet<Uri> current = new ArraySet<>();
+        evaluateRule(config.manualRule, current);
+        for (ZenRule automaticRule : config.automaticRules.values()) {
+            evaluateRule(automaticRule, current);
+        }
+        final int N = mSubscriptions.size();
+        for (int i = N - 1; i >= 0; i--) {
+            final Uri id = mSubscriptions.keyAt(i);
+            final ComponentName component = mSubscriptions.valueAt(i);
+            if (!current.contains(id)) {
+                mConditionProviders.unsubscribeIfNecessary(component, id);
+                mSubscriptions.removeAt(i);
+            }
+        }
+    }
+
+    private void evaluateRule(ZenRule rule, ArraySet<Uri> current) {
+        if (rule == null || rule.conditionId == null) return;
+        final Uri id = rule.conditionId;
+        for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
+            if (sp.isValidConditionid(id)) {
+                mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
+                rule.component = sp.getComponent();
+            }
+        }
+        current.add(id);
+        if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
+            mSubscriptions.put(rule.conditionId, rule.component);
+        }
+    }
+
+    @Override
+    public void onBootComplete() {
+        // noop
+    }
+
+    @Override
+    public void onUserSwitched() {
+        // noop
+    }
+
+    @Override
+    public void onConditionChanged(Uri id, Condition condition) {
+        if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
+        ZenModeConfig config = mHelper.getConfig();
+        if (config == null) return;
+        config = config.copy();
+        boolean updated = updateCondition(id, condition, config.manualRule);
+        for (ZenRule automaticRule : config.automaticRules.values()) {
+            updated |= updateCondition(id, condition, automaticRule);
+            updated |= updateSnoozing(automaticRule);
+        }
+        if (updated) {
+            mHelper.setConfig(config, "conditionChanged");
+        }
+    }
+
+    private boolean updateSnoozing(ZenRule rule) {
+        if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
+            rule.snoozing = false;
+            if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
+            return true;
+        }
+        return false;
+    }
+
+    private boolean updateCondition(Uri id, Condition condition, ZenRule rule) {
+        if (id == null || rule == null || rule.conditionId == null) return false;
+        if (!rule.conditionId.equals(id)) return false;
+        if (Objects.equals(condition, rule.condition)) return false;
+        rule.condition = condition;
+        return true;
+    }
+}
diff --git a/services/core/java/com/android/server/notification/ZenModeFiltering.java b/services/core/java/com/android/server/notification/ZenModeFiltering.java
new file mode 100644
index 0000000..2aaeb9d
--- /dev/null
+++ b/services/core/java/com/android/server/notification/ZenModeFiltering.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.Notification;
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
+import android.service.notification.ZenModeConfig;
+import android.telecom.TelecomManager;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.util.Date;
+import java.util.Objects;
+
+public class ZenModeFiltering {
+    private static final String TAG = ZenModeHelper.TAG;
+    private static final boolean DEBUG = ZenModeHelper.DEBUG;
+
+    static final RepeatCallers REPEAT_CALLERS = new RepeatCallers();
+
+    private final Context mContext;
+
+    private ComponentName mDefaultPhoneApp;
+
+    public ZenModeFiltering(Context context) {
+        mContext = context;
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mDefaultPhoneApp="); pw.println(mDefaultPhoneApp);
+        pw.print(prefix); pw.print("RepeatCallers.mThresholdMinutes=");
+        pw.println(REPEAT_CALLERS.mThresholdMinutes);
+        synchronized (REPEAT_CALLERS) {
+            if (!REPEAT_CALLERS.mCalls.isEmpty()) {
+                pw.print(prefix); pw.println("RepeatCallers.mCalls=");
+                for (int i = 0; i < REPEAT_CALLERS.mCalls.size(); i++) {
+                    pw.print(prefix); pw.print("  ");
+                    pw.print(REPEAT_CALLERS.mCalls.keyAt(i));
+                    pw.print(" at ");
+                    pw.println(ts(REPEAT_CALLERS.mCalls.valueAt(i)));
+                }
+            }
+        }
+    }
+
+    private static String ts(long time) {
+        return new Date(time) + " (" + time + ")";
+    }
+
+    /**
+     * @param extras extras of the notification with EXTRA_PEOPLE populated
+     * @param contactsTimeoutMs timeout in milliseconds to wait for contacts response
+     * @param timeoutAffinity affinity to return when the timeout specified via
+     *                        <code>contactsTimeoutMs</code> is hit
+     */
+    public static boolean matchesCallFilter(Context context, int zen, ZenModeConfig config,
+            UserHandle userHandle, Bundle extras, ValidateNotificationPeople validator,
+            int contactsTimeoutMs, float timeoutAffinity) {
+        if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
+        if (zen == Global.ZEN_MODE_ALARMS) return false; // not an alarm
+        if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
+            if (config.allowRepeatCallers && REPEAT_CALLERS.isRepeat(context, extras)) return true;
+            if (!config.allowCalls) return false; // no other calls get through
+            if (validator != null) {
+                final float contactAffinity = validator.getContactAffinity(userHandle, extras,
+                        contactsTimeoutMs, timeoutAffinity);
+                return audienceMatches(config, contactAffinity);
+            }
+        }
+        return true;
+    }
+
+    private static Bundle extras(NotificationRecord record) {
+        return record != null && record.sbn != null && record.sbn.getNotification() != null
+                ? record.sbn.getNotification().extras : null;
+    }
+
+    public boolean shouldIntercept(int zen, ZenModeConfig config, NotificationRecord record) {
+        if (isSystem(record)) {
+            return false;
+        }
+        switch (zen) {
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                // #notevenalarms
+                ZenLog.traceIntercepted(record, "none");
+                return true;
+            case Global.ZEN_MODE_ALARMS:
+                if (isAlarm(record)) {
+                    // Alarms only
+                    return false;
+                }
+                ZenLog.traceIntercepted(record, "alarmsOnly");
+                return true;
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                if (isAlarm(record)) {
+                    // Alarms are always priority
+                    return false;
+                }
+                // allow user-prioritized packages through in priority mode
+                if (record.getPackagePriority() == Notification.PRIORITY_MAX) {
+                    ZenLog.traceNotIntercepted(record, "priorityApp");
+                    return false;
+                }
+                if (isCall(record)) {
+                    if (config.allowRepeatCallers
+                            && REPEAT_CALLERS.isRepeat(mContext, extras(record))) {
+                        ZenLog.traceNotIntercepted(record, "repeatCaller");
+                        return false;
+                    }
+                    if (!config.allowCalls) {
+                        ZenLog.traceIntercepted(record, "!allowCalls");
+                        return true;
+                    }
+                    return shouldInterceptAudience(config, record);
+                }
+                if (isMessage(record)) {
+                    if (!config.allowMessages) {
+                        ZenLog.traceIntercepted(record, "!allowMessages");
+                        return true;
+                    }
+                    return shouldInterceptAudience(config, record);
+                }
+                if (isEvent(record)) {
+                    if (!config.allowEvents) {
+                        ZenLog.traceIntercepted(record, "!allowEvents");
+                        return true;
+                    }
+                    return false;
+                }
+                if (isReminder(record)) {
+                    if (!config.allowReminders) {
+                        ZenLog.traceIntercepted(record, "!allowReminders");
+                        return true;
+                    }
+                    return false;
+                }
+                ZenLog.traceIntercepted(record, "!priority");
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private static boolean shouldInterceptAudience(ZenModeConfig config,
+            NotificationRecord record) {
+        if (!audienceMatches(config, record.getContactAffinity())) {
+            ZenLog.traceIntercepted(record, "!audienceMatches");
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean isSystem(NotificationRecord record) {
+        return record.isCategory(Notification.CATEGORY_SYSTEM);
+    }
+
+    private static boolean isAlarm(NotificationRecord record) {
+        return record.isCategory(Notification.CATEGORY_ALARM)
+                || record.isAudioStream(AudioManager.STREAM_ALARM)
+                || record.isAudioAttributesUsage(AudioAttributes.USAGE_ALARM);
+    }
+
+    private static boolean isEvent(NotificationRecord record) {
+        return record.isCategory(Notification.CATEGORY_EVENT);
+    }
+
+    private static boolean isReminder(NotificationRecord record) {
+        return record.isCategory(Notification.CATEGORY_REMINDER);
+    }
+
+    public boolean isCall(NotificationRecord record) {
+        return record != null && (isDefaultPhoneApp(record.sbn.getPackageName())
+                || record.isCategory(Notification.CATEGORY_CALL));
+    }
+
+    private boolean isDefaultPhoneApp(String pkg) {
+        if (mDefaultPhoneApp == null) {
+            final TelecomManager telecomm =
+                    (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+            mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
+            if (DEBUG) Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
+        }
+        return pkg != null && mDefaultPhoneApp != null
+                && pkg.equals(mDefaultPhoneApp.getPackageName());
+    }
+
+    @SuppressWarnings("deprecation")
+    private boolean isDefaultMessagingApp(NotificationRecord record) {
+        final int userId = record.getUserId();
+        if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
+        final String defaultApp = Secure.getStringForUser(mContext.getContentResolver(),
+                Secure.SMS_DEFAULT_APPLICATION, userId);
+        return Objects.equals(defaultApp, record.sbn.getPackageName());
+    }
+
+    private boolean isMessage(NotificationRecord record) {
+        return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
+    }
+
+    private static boolean audienceMatches(ZenModeConfig config, float contactAffinity) {
+        switch (config.allowFrom) {
+            case ZenModeConfig.SOURCE_ANYONE:
+                return true;
+            case ZenModeConfig.SOURCE_CONTACT:
+                return contactAffinity >= ValidateNotificationPeople.VALID_CONTACT;
+            case ZenModeConfig.SOURCE_STAR:
+                return contactAffinity >= ValidateNotificationPeople.STARRED_CONTACT;
+            default:
+                Slog.w(TAG, "Encountered unknown source: " + config.allowFrom);
+                return true;
+        }
+    }
+
+    private static class RepeatCallers {
+        private final ArrayMap<String, Long> mCalls = new ArrayMap<>();
+        private int mThresholdMinutes;
+
+        private synchronized boolean isRepeat(Context context, Bundle extras) {
+            if (mThresholdMinutes <= 0) {
+                mThresholdMinutes = context.getResources().getInteger(com.android.internal.R.integer
+                        .config_zen_repeat_callers_threshold);
+            }
+            if (mThresholdMinutes <= 0 || extras == null) return false;
+            final String peopleString = peopleString(extras);
+            if (peopleString == null) return false;
+            final long now = System.currentTimeMillis();
+            final int N = mCalls.size();
+            for (int i = N - 1; i >= 0; i--) {
+                final long time = mCalls.valueAt(i);
+                if (time > now || (now - time) > mThresholdMinutes * 1000 * 60) {
+                    mCalls.removeAt(i);
+                }
+            }
+            final boolean isRepeat = mCalls.containsKey(peopleString);
+            mCalls.put(peopleString, now);
+            return isRepeat;
+        }
+
+        private static String peopleString(Bundle extras) {
+            final String[] extraPeople = ValidateNotificationPeople.getExtraPeople(extras);
+            if (extraPeople == null || extraPeople.length == 0) return null;
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < extraPeople.length; i++) {
+                String extraPerson = extraPeople[i];
+                if (extraPerson == null) continue;
+                extraPerson = extraPerson.trim();
+                if (extraPerson.isEmpty()) continue;
+                if (sb.length() > 0) {
+                    sb.append('|');
+                }
+                sb.append(extraPerson);
+            }
+            return sb.length() == 0 ? null : sb.toString();
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a985b01..e5925fe 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,14 +21,12 @@
 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
 
 import android.app.AppOpsManager;
-import android.app.Notification;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
-import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.VolumePolicy;
@@ -39,12 +37,13 @@
 import android.os.Message;
 import android.os.UserHandle;
 import android.provider.Settings.Global;
-import android.provider.Settings.Secure;
+import android.service.notification.IConditionListener;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.ZenModeConfig;
-import android.telecom.TelecomManager;
+import android.service.notification.ZenModeConfig.ScheduleInfo;
+import android.service.notification.ZenModeConfig.ZenRule;
+import android.util.ArraySet;
 import android.util.Log;
-import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.server.LocalServices;
@@ -58,14 +57,13 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Objects;
 
 /**
  * NotificationManagerService helper for functionality related to zen mode.
  */
-public class ZenModeHelper implements AudioManagerInternal.RingerModeDelegate {
-    private static final String TAG = "ZenModeHelper";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+public class ZenModeHelper {
+    static final String TAG = "ZenModeHelper";
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final Context mContext;
     private final H mHandler;
@@ -73,38 +71,46 @@
     private final AppOpsManager mAppOps;
     private final ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
+    private final ZenModeFiltering mFiltering;
+    private final RingerModeDelegate mRingerModeDelegate = new RingerModeDelegate();
+    private final ZenModeConditions mConditions;
 
-    private ComponentName mDefaultPhoneApp;
     private int mZenMode;
     private ZenModeConfig mConfig;
     private AudioManagerInternal mAudioManager;
     private int mPreviousRingerMode = -1;
     private boolean mEffectsSuppressed;
 
-    public ZenModeHelper(Context context, Looper looper) {
+    public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
         mContext = context;
         mHandler = new H(looper);
         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mDefaultConfig = readDefaultConfig(context.getResources());
+        appendDefaultScheduleRules(mDefaultConfig);
         mConfig = mDefaultConfig;
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
+        mFiltering = new ZenModeFiltering(mContext);
+        mConditions = new ZenModeConditions(this, conditionProviders);
     }
 
-    public static ZenModeConfig readDefaultConfig(Resources resources) {
-        XmlResourceParser parser = null;
-        try {
-            parser = resources.getXml(R.xml.default_zen_mode_config);
-            while (parser.next() != XmlPullParser.END_DOCUMENT) {
-                final ZenModeConfig config = ZenModeConfig.readXml(parser);
-                if (config != null) return config;
-            }
-        } catch (Exception e) {
-            Slog.w(TAG, "Error reading default zen mode config from resource", e);
-        } finally {
-            IoUtils.closeQuietly(parser);
-        }
-        return new ZenModeConfig();
+    @Override
+    public String toString() {
+        return TAG;
+    }
+
+    public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
+            ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
+        return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle, extras,
+                validator, contactsTimeoutMs, timeoutAffinity);
+    }
+
+    public boolean isCall(NotificationRecord record) {
+        return mFiltering.isCall(record);
+    }
+
+    public boolean shouldIntercept(NotificationRecord record) {
+        return mFiltering.shouldIntercept(mZenMode, mConfig, record);
     }
 
     public void addCallback(Callback callback) {
@@ -115,44 +121,32 @@
         mCallbacks.remove(callback);
     }
 
+    public void initZenMode() {
+        if (DEBUG) Log.d(TAG, "initZenMode");
+        evaluateZenMode("init", true /*setRingerMode*/);
+    }
+
     public void onSystemReady() {
+        if (DEBUG) Log.d(TAG, "onSystemReady");
         mAudioManager = LocalServices.getService(AudioManagerInternal.class);
         if (mAudioManager != null) {
-            mAudioManager.setRingerModeDelegate(this);
+            mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
         }
     }
 
+    public void requestZenModeConditions(IConditionListener callback, int relevance) {
+        mConditions.requestConditions(callback, relevance);
+    }
+
     public int getZenModeListenerInterruptionFilter() {
-        switch (mZenMode) {
-            case Global.ZEN_MODE_OFF:
-                return NotificationListenerService.INTERRUPTION_FILTER_ALL;
-            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
-                return NotificationListenerService.INTERRUPTION_FILTER_PRIORITY;
-            case Global.ZEN_MODE_NO_INTERRUPTIONS:
-                return NotificationListenerService.INTERRUPTION_FILTER_NONE;
-            default:
-                return 0;
-        }
-    }
-
-    private static int zenModeFromListenerInterruptionFilter(int listenerInterruptionFilter,
-            int defValue) {
-        switch (listenerInterruptionFilter) {
-            case NotificationListenerService.INTERRUPTION_FILTER_ALL:
-                return Global.ZEN_MODE_OFF;
-            case NotificationListenerService.INTERRUPTION_FILTER_PRIORITY:
-                return Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-            case NotificationListenerService.INTERRUPTION_FILTER_NONE:
-                return Global.ZEN_MODE_NO_INTERRUPTIONS;
-            default:
-                return defValue;
-        }
+        return getZenModeListenerInterruptionFilter(mZenMode);
     }
 
     public void requestFromListener(ComponentName name, int interruptionFilter) {
         final int newZen = zenModeFromListenerInterruptionFilter(interruptionFilter, -1);
         if (newZen != -1) {
-            setZenMode(newZen, "listener:" + (name != null ? name.flattenToShortString() : null));
+            setManualZenMode(newZen, null,
+                    "listener:" + (name != null ? name.flattenToShortString() : null));
         }
     }
 
@@ -162,86 +156,144 @@
         applyRestrictions();
     }
 
-    public boolean shouldIntercept(NotificationRecord record) {
-        if (isSystem(record)) {
-            return false;
-        }
-        switch (mZenMode) {
-            case Global.ZEN_MODE_NO_INTERRUPTIONS:
-                // #notevenalarms
-                ZenLog.traceIntercepted(record, "none");
-                return true;
-            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
-                if (isAlarm(record)) {
-                    // Alarms are always priority
-                    return false;
-                }
-                // allow user-prioritized packages through in priority mode
-                if (record.getPackagePriority() == Notification.PRIORITY_MAX) {
-                    ZenLog.traceNotIntercepted(record, "priorityApp");
-                    return false;
-                }
-                if (isCall(record)) {
-                    if (!mConfig.allowCalls) {
-                        ZenLog.traceIntercepted(record, "!allowCalls");
-                        return true;
-                    }
-                    return shouldInterceptAudience(record);
-                }
-                if (isMessage(record)) {
-                    if (!mConfig.allowMessages) {
-                        ZenLog.traceIntercepted(record, "!allowMessages");
-                        return true;
-                    }
-                    return shouldInterceptAudience(record);
-                }
-                if (isEvent(record)) {
-                    if (!mConfig.allowEvents) {
-                        ZenLog.traceIntercepted(record, "!allowEvents");
-                        return true;
-                    }
-                    return false;
-                }
-                ZenLog.traceIntercepted(record, "!priority");
-                return true;
-            default:
-                return false;
-        }
-    }
-
-    private boolean shouldInterceptAudience(NotificationRecord record) {
-        if (!audienceMatches(record.getContactAffinity())) {
-            ZenLog.traceIntercepted(record, "!audienceMatches");
-            return true;
-        }
-        return false;
-    }
-
     public int getZenMode() {
         return mZenMode;
     }
 
-    public void setZenMode(int zenMode, String reason) {
-        setZenMode(zenMode, reason, true);
+    public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
+        setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/);
     }
 
-    private void setZenMode(int zenMode, String reason, boolean setRingerMode) {
-        ZenLog.traceSetZenMode(zenMode, reason);
-        if (mZenMode == zenMode) return;
-        ZenLog.traceUpdateZenMode(mZenMode, zenMode);
-        mZenMode = zenMode;
-        Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, mZenMode);
+    private void setManualZenMode(int zenMode, Uri conditionId, String reason,
+            boolean setRingerMode) {
+        if (mConfig == null) return;
+        if (!Global.isValidZenMode(zenMode)) return;
+        if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
+                + " conditionId=" + conditionId + " reason=" + reason
+                + " setRingerMode=" + setRingerMode);
+        final ZenModeConfig newConfig = mConfig.copy();
+        if (zenMode == Global.ZEN_MODE_OFF) {
+            newConfig.manualRule = null;
+            for (ZenRule automaticRule : newConfig.automaticRules.values()) {
+                if (automaticRule.isTrueOrUnknown()) {
+                    automaticRule.snoozing = true;
+                }
+            }
+        } else {
+            final ZenRule newRule = new ZenRule();
+            newRule.enabled = true;
+            newRule.zenMode = zenMode;
+            newRule.conditionId = conditionId;
+            newConfig.manualRule = newRule;
+        }
+        setConfig(newConfig, reason, setRingerMode);
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("mZenMode=");
+        pw.println(Global.zenModeToString(mZenMode));
+        dump(pw, prefix, "mConfig", mConfig);
+        dump(pw, prefix, "mDefaultConfig", mDefaultConfig);
+        pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
+        pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
+        mFiltering.dump(pw, prefix);
+        mConditions.dump(pw, prefix);
+    }
+
+    private static void dump(PrintWriter pw, String prefix, String var, ZenModeConfig config) {
+        pw.print(prefix); pw.print(var); pw.print('=');
+        if (config == null) {
+            pw.println(config);
+            return;
+        }
+        pw.printf("allow(calls=%s,repeatCallers=%s,events=%s,from=%s,messages=%s,reminders=%s)\n",
+                config.allowCalls, config.allowRepeatCallers, config.allowEvents, config.allowFrom,
+                config.allowMessages, config.allowReminders);
+        pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
+        if (config.automaticRules.isEmpty()) return;
+        final int N = config.automaticRules.size();
+        for (int i = 0; i < N; i++) {
+            pw.print(prefix); pw.print(i == 0 ? "  automaticRules=" : "                 ");
+            pw.println(config.automaticRules.valueAt(i));
+        }
+    }
+
+    public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
+        final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
+        if (config != null) {
+            if (DEBUG) Log.d(TAG, "readXml");
+            setConfig(config, "readXml");
+        }
+    }
+
+    public void writeXml(XmlSerializer out) throws IOException {
+        mConfig.writeXml(out);
+    }
+
+    public ZenModeConfig getConfig() {
+        return mConfig;
+    }
+
+    public boolean setConfig(ZenModeConfig config, String reason) {
+        return setConfig(config, reason, true /*setRingerMode*/);
+    }
+
+    private boolean setConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+        if (config == null || !config.isValid()) {
+            Log.w(TAG, "Invalid config in setConfig; " + config);
+            return false;
+        }
+        mConditions.evaluateConfig(config);  // may modify config
+        if (config.equals(mConfig)) return true;
+        if (DEBUG) Log.d(TAG, "setConfig reason=" + reason);
+        ZenLog.traceConfig(mConfig, config);
+        mConfig = config;
+        dispatchOnConfigChanged();
+        final String val = Integer.toString(mConfig.hashCode());
+        Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+        if (!evaluateZenMode(reason, setRingerMode)) {
+            applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
+        }
+        return true;
+    }
+
+    private int getZenModeSetting() {
+        return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
+    }
+
+    private void setZenModeSetting(int zen) {
+        Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zen);
+    }
+
+    private boolean evaluateZenMode(String reason, boolean setRingerMode) {
+        if (DEBUG) Log.d(TAG, "evaluateZenMode");
+        final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>();
+        final int zen = computeZenMode(automaticRules);
+        if (zen == mZenMode) return false;
+        ZenLog.traceSetZenMode(zen, reason);
+        mZenMode = zen;
+        setZenModeSetting(mZenMode);
         if (setRingerMode) {
             applyZenToRingerMode();
         }
         applyRestrictions();
         mHandler.postDispatchOnZenModeChanged();
+        return true;
     }
 
-    public void readZenModeFromSetting() {
-        final int newMode = Global.getInt(mContext.getContentResolver(),
-                Global.ZEN_MODE, Global.ZEN_MODE_OFF);
-        setZenMode(newMode, "setting");
+    private int computeZenMode(ArraySet<ZenRule> automaticRulesOut) {
+        if (mConfig == null) return Global.ZEN_MODE_OFF;
+        if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
+        int zen = Global.ZEN_MODE_OFF;
+        for (ZenRule automaticRule : mConfig.automaticRules.values()) {
+            if (automaticRule.enabled && !automaticRule.snoozing
+                    && automaticRule.isTrueOrUnknown()) {
+                if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
+                    zen = automaticRule.zenMode;
+                }
+            }
+        }
+        return zen;
     }
 
     private void applyRestrictions() {
@@ -252,7 +304,8 @@
         applyRestrictions(muteNotifications, USAGE_NOTIFICATION);
 
         // call restrictions
-        final boolean muteCalls = zen && !mConfig.allowCalls || mEffectsSuppressed;
+        final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
+                || mEffectsSuppressed;
         applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);
 
         // alarm restrictions
@@ -270,43 +323,6 @@
                 exceptionPackages);
     }
 
-    public void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("mZenMode=");
-        pw.println(Global.zenModeToString(mZenMode));
-        pw.print(prefix); pw.print("mConfig="); pw.println(mConfig);
-        pw.print(prefix); pw.print("mDefaultConfig="); pw.println(mDefaultConfig);
-        pw.print(prefix); pw.print("mPreviousRingerMode="); pw.println(mPreviousRingerMode);
-        pw.print(prefix); pw.print("mDefaultPhoneApp="); pw.println(mDefaultPhoneApp);
-        pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
-    }
-
-    public void readXml(XmlPullParser parser) throws XmlPullParserException, IOException {
-        final ZenModeConfig config = ZenModeConfig.readXml(parser);
-        if (config != null) {
-            setConfig(config);
-        }
-    }
-
-    public void writeXml(XmlSerializer out) throws IOException {
-        mConfig.writeXml(out);
-    }
-
-    public ZenModeConfig getConfig() {
-        return mConfig;
-    }
-
-    public boolean setConfig(ZenModeConfig config) {
-        if (config == null || !config.isValid()) return false;
-        if (config.equals(mConfig)) return true;
-        ZenLog.traceConfig(mConfig, config);
-        mConfig = config;
-        dispatchOnConfigChanged();
-        final String val = Integer.toString(mConfig.hashCode());
-        Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
-        applyRestrictions();
-        return true;
-    }
-
     private void applyZenToRingerMode() {
         if (mAudioManager == null) return;
         // force the ringer mode into compliance
@@ -314,6 +330,7 @@
         int newRingerModeInternal = ringerModeInternal;
         switch (mZenMode) {
             case Global.ZEN_MODE_NO_INTERRUPTIONS:
+            case Global.ZEN_MODE_ALARMS:
                 if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) {
                     mPreviousRingerMode = ringerModeInternal;
                     newRingerModeInternal = AudioManager.RINGER_MODE_SILENT;
@@ -333,79 +350,6 @@
         }
     }
 
-    @Override  // RingerModeDelegate
-    public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
-            int ringerModeExternal, VolumePolicy policy) {
-        final boolean isChange = ringerModeOld != ringerModeNew;
-
-        int ringerModeExternalOut = ringerModeNew;
-
-        int newZen = -1;
-        switch (ringerModeNew) {
-            case AudioManager.RINGER_MODE_SILENT:
-                if (isChange && policy.doNotDisturbWhenSilent) {
-                    if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS) {
-                        newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
-                    }
-                }
-                break;
-            case AudioManager.RINGER_MODE_VIBRATE:
-            case AudioManager.RINGER_MODE_NORMAL:
-                if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
-                        && mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
-                    newZen = Global.ZEN_MODE_OFF;
-                } else if (mZenMode != Global.ZEN_MODE_OFF) {
-                    ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
-                }
-                break;
-        }
-        if (newZen != -1) {
-            setZenMode(newZen, "ringerModeInternal", false /*setRingerMode*/);
-        }
-
-        if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
-            ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
-                    ringerModeExternal, ringerModeExternalOut);
-        }
-        return ringerModeExternalOut;
-    }
-
-    @Override  // RingerModeDelegate
-    public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
-            int ringerModeInternal, VolumePolicy policy) {
-        int ringerModeInternalOut = ringerModeNew;
-        final boolean isChange = ringerModeOld != ringerModeNew;
-        final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
-
-        int newZen = -1;
-        switch (ringerModeNew) {
-            case AudioManager.RINGER_MODE_SILENT:
-                if (isChange) {
-                    if (mZenMode == Global.ZEN_MODE_OFF) {
-                        newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-                    }
-                    ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
-                            : AudioManager.RINGER_MODE_NORMAL;
-                } else {
-                    ringerModeInternalOut = ringerModeInternal;
-                }
-                break;
-            case AudioManager.RINGER_MODE_VIBRATE:
-            case AudioManager.RINGER_MODE_NORMAL:
-                if (mZenMode != Global.ZEN_MODE_OFF) {
-                    newZen = Global.ZEN_MODE_OFF;
-                }
-                break;
-        }
-        if (newZen != -1) {
-            setZenMode(newZen, "ringerModeExternal", false /*setRingerMode*/);
-        }
-
-        ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller, ringerModeInternal,
-                ringerModeInternalOut);
-        return ringerModeInternalOut;
-    }
-
     private void dispatchOnConfigChanged() {
         for (Callback callback : mCallbacks) {
             callback.onConfigChanged();
@@ -418,89 +362,210 @@
         }
     }
 
-    private static boolean isSystem(NotificationRecord record) {
-        return record.isCategory(Notification.CATEGORY_SYSTEM);
-    }
-
-    private static boolean isAlarm(NotificationRecord record) {
-        return record.isCategory(Notification.CATEGORY_ALARM)
-                || record.isAudioStream(AudioManager.STREAM_ALARM)
-                || record.isAudioAttributesUsage(AudioAttributes.USAGE_ALARM);
-    }
-
-    private static boolean isEvent(NotificationRecord record) {
-        return record.isCategory(Notification.CATEGORY_EVENT);
-    }
-
-    public boolean isCall(NotificationRecord record) {
-        return record != null && (isDefaultPhoneApp(record.sbn.getPackageName())
-                || record.isCategory(Notification.CATEGORY_CALL));
-    }
-
-    private boolean isDefaultPhoneApp(String pkg) {
-        if (mDefaultPhoneApp == null) {
-            final TelecomManager telecomm =
-                    (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
-            mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
-            if (DEBUG) Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
-        }
-        return pkg != null && mDefaultPhoneApp != null
-                && pkg.equals(mDefaultPhoneApp.getPackageName());
-    }
-
-    private boolean isDefaultMessagingApp(NotificationRecord record) {
-        final int userId = record.getUserId();
-        if (userId == UserHandle.USER_NULL || userId == UserHandle.USER_ALL) return false;
-        final String defaultApp = Secure.getStringForUser(mContext.getContentResolver(),
-                Secure.SMS_DEFAULT_APPLICATION, userId);
-        return Objects.equals(defaultApp, record.sbn.getPackageName());
-    }
-
-    private boolean isMessage(NotificationRecord record) {
-        return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
-    }
-
-    /**
-     * @param extras extras of the notification with EXTRA_PEOPLE populated
-     * @param contactsTimeoutMs timeout in milliseconds to wait for contacts response
-     * @param timeoutAffinity affinity to return when the timeout specified via
-     *                        <code>contactsTimeoutMs</code> is hit
-     */
-    public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
-            ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
-        final int zen = mZenMode;
-        if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
-        if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
-            if (!mConfig.allowCalls) return false; // no calls get through
-            if (validator != null) {
-                final float contactAffinity = validator.getContactAffinity(userHandle, extras,
-                        contactsTimeoutMs, timeoutAffinity);
-                return audienceMatches(contactAffinity);
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public String toString() {
-        return TAG;
-    }
-
-    private boolean audienceMatches(float contactAffinity) {
-        switch (mConfig.allowFrom) {
-            case ZenModeConfig.SOURCE_ANYONE:
-                return true;
-            case ZenModeConfig.SOURCE_CONTACT:
-                return contactAffinity >= ValidateNotificationPeople.VALID_CONTACT;
-            case ZenModeConfig.SOURCE_STAR:
-                return contactAffinity >= ValidateNotificationPeople.STARRED_CONTACT;
+    private static int getZenModeListenerInterruptionFilter(int zen) {
+        switch (zen) {
+            case Global.ZEN_MODE_OFF:
+                return NotificationListenerService.INTERRUPTION_FILTER_ALL;
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
+                return NotificationListenerService.INTERRUPTION_FILTER_PRIORITY;
+            case Global.ZEN_MODE_ALARMS:
+                return NotificationListenerService.INTERRUPTION_FILTER_ALARMS;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS:
+                return NotificationListenerService.INTERRUPTION_FILTER_NONE;
             default:
-                Slog.w(TAG, "Encountered unknown source: " + mConfig.allowFrom);
-                return true;
+                return 0;
         }
     }
 
-    private class SettingsObserver extends ContentObserver {
+    private static int zenModeFromListenerInterruptionFilter(int listenerInterruptionFilter,
+            int defValue) {
+        switch (listenerInterruptionFilter) {
+            case NotificationListenerService.INTERRUPTION_FILTER_ALL:
+                return Global.ZEN_MODE_OFF;
+            case NotificationListenerService.INTERRUPTION_FILTER_PRIORITY:
+                return Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+            case NotificationListenerService.INTERRUPTION_FILTER_ALARMS:
+                return Global.ZEN_MODE_ALARMS;
+            case NotificationListenerService.INTERRUPTION_FILTER_NONE:
+                return Global.ZEN_MODE_NO_INTERRUPTIONS;
+            default:
+                return defValue;
+        }
+    }
+
+    private ZenModeConfig readDefaultConfig(Resources resources) {
+        XmlResourceParser parser = null;
+        try {
+            parser = resources.getXml(R.xml.default_zen_mode_config);
+            while (parser.next() != XmlPullParser.END_DOCUMENT) {
+                final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
+                if (config != null) return config;
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Error reading default zen mode config from resource", e);
+        } finally {
+            IoUtils.closeQuietly(parser);
+        }
+        return new ZenModeConfig();
+    }
+
+    private void appendDefaultScheduleRules(ZenModeConfig config) {
+        if (config == null) return;
+
+        final ScheduleInfo weeknights = new ScheduleInfo();
+        weeknights.days = ZenModeConfig.WEEKNIGHT_DAYS;
+        weeknights.startHour = 22;
+        weeknights.endHour = 7;
+        final ZenRule rule1 = new ZenRule();
+        rule1.enabled = false;
+        rule1.name = mContext.getResources()
+                .getString(R.string.zen_mode_default_weeknights_name);
+        rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
+        rule1.zenMode = Global.ZEN_MODE_ALARMS;
+        config.automaticRules.put(config.newRuleId(), rule1);
+
+        final ScheduleInfo weekends = new ScheduleInfo();
+        weekends.days = ZenModeConfig.WEEKEND_DAYS;
+        weekends.startHour = 23;
+        weekends.startMinute = 30;
+        weekends.endHour = 10;
+        final ZenRule rule2 = new ZenRule();
+        rule2.enabled = false;
+        rule2.name = mContext.getResources()
+                .getString(R.string.zen_mode_default_weekends_name);
+        rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
+        rule2.zenMode = Global.ZEN_MODE_ALARMS;
+        config.automaticRules.put(config.newRuleId(), rule2);
+    }
+
+    private static int zenSeverity(int zen) {
+        switch (zen) {
+            case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: return 1;
+            case Global.ZEN_MODE_ALARMS: return 2;
+            case Global.ZEN_MODE_NO_INTERRUPTIONS: return 3;
+            default: return 0;
+        }
+    }
+
+    private final ZenModeConfig.Migration mConfigMigration = new ZenModeConfig.Migration() {
+        @Override
+        public ZenModeConfig migrate(ZenModeConfig.XmlV1 v1) {
+            if (v1 == null) return null;
+            final ZenModeConfig rt = new ZenModeConfig();
+            rt.allowCalls = v1.allowCalls;
+            rt.allowEvents = v1.allowEvents;
+            rt.allowFrom = v1.allowFrom;
+            rt.allowMessages = v1.allowMessages;
+            rt.allowReminders = v1.allowReminders;
+            // don't migrate current exit condition
+            final int[] days = ZenModeConfig.XmlV1.tryParseDays(v1.sleepMode);
+            if (days != null && days.length > 0) {
+                Log.i(TAG, "Migrating existing V1 downtime to single schedule");
+                final ScheduleInfo schedule = new ScheduleInfo();
+                schedule.days = days;
+                schedule.startHour = v1.sleepStartHour;
+                schedule.startMinute = v1.sleepStartMinute;
+                schedule.endHour = v1.sleepEndHour;
+                schedule.endMinute = v1.sleepEndMinute;
+                final ZenRule rule = new ZenRule();
+                rule.enabled = true;
+                rule.name = mContext.getResources()
+                        .getString(R.string.zen_mode_downtime_feature_name);
+                rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
+                rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
+                        : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+                rt.automaticRules.put(rt.newRuleId(), rule);
+            } else {
+                Log.i(TAG, "No existing V1 downtime found, generating default schedules");
+                appendDefaultScheduleRules(rt);
+            }
+            return rt;
+        }
+    };
+
+    private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate {
+        @Override
+        public String toString() {
+            return TAG;
+        }
+
+        @Override
+        public int onSetRingerModeInternal(int ringerModeOld, int ringerModeNew, String caller,
+                int ringerModeExternal, VolumePolicy policy) {
+            final boolean isChange = ringerModeOld != ringerModeNew;
+
+            int ringerModeExternalOut = ringerModeNew;
+
+            int newZen = -1;
+            switch (ringerModeNew) {
+                case AudioManager.RINGER_MODE_SILENT:
+                    if (isChange && policy.doNotDisturbWhenSilent) {
+                        if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
+                                && mZenMode != Global.ZEN_MODE_ALARMS) {
+                            newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
+                        }
+                    }
+                    break;
+                case AudioManager.RINGER_MODE_VIBRATE:
+                case AudioManager.RINGER_MODE_NORMAL:
+                    if (isChange && ringerModeOld == AudioManager.RINGER_MODE_SILENT
+                            && (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS
+                                    || mZenMode == Global.ZEN_MODE_ALARMS)) {
+                        newZen = Global.ZEN_MODE_OFF;
+                    } else if (mZenMode != Global.ZEN_MODE_OFF) {
+                        ringerModeExternalOut = AudioManager.RINGER_MODE_SILENT;
+                    }
+                    break;
+            }
+            if (newZen != -1) {
+                setManualZenMode(newZen, null, "ringerModeInternal", false /*setRingerMode*/);
+            }
+
+            if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) {
+                ZenLog.traceSetRingerModeInternal(ringerModeOld, ringerModeNew, caller,
+                        ringerModeExternal, ringerModeExternalOut);
+            }
+            return ringerModeExternalOut;
+        }
+
+        @Override
+        public int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller,
+                int ringerModeInternal, VolumePolicy policy) {
+            int ringerModeInternalOut = ringerModeNew;
+            final boolean isChange = ringerModeOld != ringerModeNew;
+            final boolean isVibrate = ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE;
+
+            int newZen = -1;
+            switch (ringerModeNew) {
+                case AudioManager.RINGER_MODE_SILENT:
+                    if (isChange) {
+                        if (mZenMode == Global.ZEN_MODE_OFF) {
+                            newZen = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+                        }
+                        ringerModeInternalOut = isVibrate ? AudioManager.RINGER_MODE_VIBRATE
+                                : AudioManager.RINGER_MODE_NORMAL;
+                    } else {
+                        ringerModeInternalOut = ringerModeInternal;
+                    }
+                    break;
+                case AudioManager.RINGER_MODE_VIBRATE:
+                case AudioManager.RINGER_MODE_NORMAL:
+                    if (mZenMode != Global.ZEN_MODE_OFF) {
+                        newZen = Global.ZEN_MODE_OFF;
+                    }
+                    break;
+            }
+            if (newZen != -1) {
+                setManualZenMode(newZen, null, "ringerModeExternal", false /*setRingerMode*/);
+            }
+
+            ZenLog.traceSetRingerModeExternal(ringerModeOld, ringerModeNew, caller,
+                    ringerModeInternal, ringerModeInternalOut);
+            return ringerModeInternalOut;
+        }
+    }
+
+    private final class SettingsObserver extends ContentObserver {
         private final Uri ZEN_MODE = Global.getUriFor(Global.ZEN_MODE);
 
         public SettingsObserver(Handler handler) {
@@ -520,12 +585,15 @@
 
         public void update(Uri uri) {
             if (ZEN_MODE.equals(uri)) {
-                readZenModeFromSetting();
+                if (mZenMode != getZenModeSetting()) {
+                    if (DEBUG) Log.d(TAG, "Fixing zen mode setting");
+                    setZenModeSetting(mZenMode);
+                }
             }
         }
     }
 
-    private class H extends Handler {
+    private final class H extends Handler {
         private static final int MSG_DISPATCH = 1;
 
         private H(Looper looper) {
@@ -551,4 +619,5 @@
         void onConfigChanged() {}
         void onZenModeChanged() {}
     }
+
 }
diff --git a/services/core/java/com/android/server/pm/BasePermission.java b/services/core/java/com/android/server/pm/BasePermission.java
index ec290ef..30f8b37 100644
--- a/services/core/java/com/android/server/pm/BasePermission.java
+++ b/services/core/java/com/android/server/pm/BasePermission.java
@@ -74,10 +74,6 @@
         this.perUser = perUser;
     }
 
-    public boolean hasGids() {
-        return ArrayUtils.isEmpty(gids);
-    }
-
     public int[] computeGids(int userId) {
         if (perUser) {
             final int[] userGids = new int[gids.length];
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 5cde8ea..ce31f98 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,10 +16,13 @@
 
 package com.android.server.pm;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageStats;
 import android.os.Build;
+import android.text.TextUtils;
 import android.util.Slog;
+
 import dalvik.system.VMRuntime;
 
 import com.android.internal.os.InstallerConnection;
@@ -41,9 +44,24 @@
         ping();
     }
 
+    private static String escapeNull(String arg) {
+        if (TextUtils.isEmpty(arg)) {
+            return "!";
+        } else {
+            return arg;
+        }
+    }
+
+    @Deprecated
     public int install(String name, int uid, int gid, String seinfo) {
+        return install(null, name, uid, gid, seinfo);
+    }
+
+    public int install(String uuid, String name, int uid, int gid, String seinfo) {
         StringBuilder builder = new StringBuilder("install");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(uid);
@@ -54,43 +72,26 @@
         return mInstaller.execute(builder.toString());
     }
 
-    public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet) {
+    public int dexopt(String apkPath, int uid, boolean isPublic,
+            String instructionSet, int dexoptNeeded) {
         if (!isValidInstructionSet(instructionSet)) {
             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
             return -1;
         }
 
-        return mInstaller.patchoat(apkPath, uid, isPublic, pkgName, instructionSet);
-    }
-
-    public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
-    }
-
-    public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
-        if (!isValidInstructionSet(instructionSet)) {
-            Slog.e(TAG, "Invalid instruction set: " + instructionSet);
-            return -1;
-        }
-
-        return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
+        return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded);
     }
 
     public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, boolean vmSafeMode, boolean debuggable) {
+            String instructionSet, int dexoptNeeded, boolean vmSafeMode,
+            boolean debuggable, @Nullable String outputPath) {
         if (!isValidInstructionSet(instructionSet)) {
             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
             return -1;
         }
-
-        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode,
-                debuggable);
+        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
+                instructionSet, dexoptNeeded, vmSafeMode,
+                debuggable, outputPath);
     }
 
     public int idmap(String targetApkPath, String overlayApkPath, int uid) {
@@ -134,9 +135,26 @@
         return mInstaller.execute(builder.toString());
     }
 
+    /**
+     * Removes packageDir or its subdirectory
+     */
+    public int rmPackageDir(String packageDir) {
+        StringBuilder builder = new StringBuilder("rmpackagedir");
+        builder.append(' ');
+        builder.append(packageDir);
+        return mInstaller.execute(builder.toString());
+    }
+
+    @Deprecated
     public int remove(String name, int userId) {
+        return remove(null, name, userId);
+    }
+
+    public int remove(String uuid, String name, int userId) {
         StringBuilder builder = new StringBuilder("remove");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(userId);
@@ -152,9 +170,16 @@
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int fixUid(String name, int uid, int gid) {
+        return fixUid(null, name, uid, gid);
+    }
+
+    public int fixUid(String uuid, String name, int uid, int gid) {
         StringBuilder builder = new StringBuilder("fixuid");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(uid);
@@ -163,27 +188,48 @@
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int deleteCacheFiles(String name, int userId) {
+        return deleteCacheFiles(null, name, userId);
+    }
+
+    public int deleteCacheFiles(String uuid, String name, int userId) {
         StringBuilder builder = new StringBuilder("rmcache");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(userId);
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int deleteCodeCacheFiles(String name, int userId) {
+        return deleteCodeCacheFiles(null, name, userId);
+    }
+
+    public int deleteCodeCacheFiles(String uuid, String name, int userId) {
         StringBuilder builder = new StringBuilder("rmcodecache");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(userId);
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int createUserData(String name, int uid, int userId, String seinfo) {
+        return createUserData(null, name, uid, userId, seinfo);
+    }
+
+    public int createUserData(String uuid, String name, int uid, int userId, String seinfo) {
         StringBuilder builder = new StringBuilder("mkuserdata");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(uid);
@@ -201,16 +247,30 @@
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int removeUserDataDirs(int userId) {
+        return removeUserDataDirs(null, userId);
+    }
+
+    public int removeUserDataDirs(String uuid, int userId) {
         StringBuilder builder = new StringBuilder("rmuser");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(userId);
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int clearUserData(String name, int userId) {
+        return clearUserData(null, name, userId);
+    }
+
+    public int clearUserData(String uuid, String name, int userId) {
         StringBuilder builder = new StringBuilder("rmuserdata");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(name);
         builder.append(' ');
         builder.append(userId);
@@ -237,15 +297,30 @@
         }
     }
 
+    @Deprecated
     public int freeCache(long freeStorageSize) {
+        return freeCache(null, freeStorageSize);
+    }
+
+    public int freeCache(String uuid, long freeStorageSize) {
         StringBuilder builder = new StringBuilder("freecache");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(String.valueOf(freeStorageSize));
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
             String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
+        return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath,
+                instructionSets, pStats);
+    }
+
+    public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath,
+            String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets,
+            PackageStats pStats) {
         for (String instructionSet : instructionSets) {
             if (!isValidInstructionSet(instructionSet)) {
                 Slog.e(TAG, "Invalid instruction set: " + instructionSet);
@@ -255,6 +330,8 @@
 
         StringBuilder builder = new StringBuilder("getsize");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(pkgName);
         builder.append(' ');
         builder.append(persona);
@@ -294,6 +371,11 @@
         return mInstaller.execute("movefiles");
     }
 
+    @Deprecated
+    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
+        return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId);
+    }
+
     /**
      * Links the 32 bit native library directory in an application's data directory to the
      * real location for backward compatibility. Note that no such symlink is created for
@@ -301,7 +383,8 @@
      *
      * @return -1 on error
      */
-    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
+    public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
+            int userId) {
         if (dataPath == null) {
             Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
             return -1;
@@ -310,7 +393,10 @@
             return -1;
         }
 
-        StringBuilder builder = new StringBuilder("linklib ");
+        StringBuilder builder = new StringBuilder("linklib");
+        builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(dataPath);
         builder.append(' ');
         builder.append(nativeLibPath32);
@@ -320,9 +406,16 @@
         return mInstaller.execute(builder.toString());
     }
 
+    @Deprecated
     public boolean restoreconData(String pkgName, String seinfo, int uid) {
+        return restoreconData(null, pkgName, seinfo, uid);
+    }
+
+    public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) {
         StringBuilder builder = new StringBuilder("restorecondata");
         builder.append(' ');
+        builder.append(escapeNull(uuid));
+        builder.append(' ');
         builder.append(pkgName);
         builder.append(' ');
         builder.append(seinfo != null ? seinfo : "!");
@@ -331,6 +424,15 @@
         return (mInstaller.execute(builder.toString()) == 0);
     }
 
+    public int createOatDir(String oatDir, String dexInstructionSet) {
+        StringBuilder builder = new StringBuilder("createoatdir");
+        builder.append(' ');
+        builder.append(oatDir);
+        builder.append(' ');
+        builder.append(dexInstructionSet);
+        return mInstaller.execute(builder.toString());
+    }
+
     /**
      * Returns true iff. {@code instructionSet} is a valid instruction set.
      */
diff --git a/services/core/java/com/android/server/pm/InstructionSets.java b/services/core/java/com/android/server/pm/InstructionSets.java
index 79e7a20..5092ebf 100644
--- a/services/core/java/com/android/server/pm/InstructionSets.java
+++ b/services/core/java/com/android/server/pm/InstructionSets.java
@@ -74,6 +74,7 @@
      * a native bridge this might be different than the one shared libraries use.
      */
     public static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+        // TODO b/19550105 Build mapping once instead of querying each time
         String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
         return TextUtils.isEmpty(dexCodeIsa) ? sharedLibraryIsa : dexCodeIsa;
     }
@@ -111,4 +112,13 @@
 
         return allInstructionSets;
     }
+
+    public static String getPrimaryInstructionSet(ApplicationInfo info) {
+        if (info.primaryCpuAbi == null) {
+            return getPreferredInstructionSet();
+        }
+
+        return VMRuntime.getInstructionSet(info.primaryCpuAbi);
+    }
+
 }
diff --git a/services/core/java/com/android/server/pm/KeySetHandle.java b/services/core/java/com/android/server/pm/KeySetHandle.java
index 640feb3..f34bd60 100644
--- a/services/core/java/com/android/server/pm/KeySetHandle.java
+++ b/services/core/java/com/android/server/pm/KeySetHandle.java
@@ -18,5 +18,46 @@
 
 import android.os.Binder;
 
-public class KeySetHandle extends Binder {
-}
\ No newline at end of file
+class KeySetHandle extends Binder{
+    private final long mId;
+    private int mRefCount;
+
+    protected KeySetHandle(long id) {
+        mId = id;
+        mRefCount = 1;
+    }
+
+    /*
+     * Only used when reading state from packages.xml
+     */
+    protected KeySetHandle(long id, int refCount) {
+        mId = id;
+        mRefCount = refCount;
+    }
+
+    public long getId() {
+        return mId;
+    }
+
+    protected int getRefCountLPr() {
+        return mRefCount;
+    }
+
+    /*
+     * Only used when reading state from packages.xml
+     */
+    protected void setRefCountLPw(int newCount) {
+         mRefCount = newCount;
+         return;
+    }
+
+    protected void incrRefCountLPw() {
+        mRefCount++;
+        return;
+    }
+
+    protected int decrRefCountLPw() {
+        mRefCount--;
+        return mRefCount;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index aa63932..db3ae91 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import android.content.pm.PackageParser;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Base64;
 import android.util.Slog;
@@ -25,7 +26,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.security.PublicKey;
-import java.util.Map;
 import java.util.Set;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -52,19 +52,61 @@
 
     private final LongSparseArray<KeySetHandle> mKeySets;
 
-    private final LongSparseArray<PublicKey> mPublicKeys;
+    private final LongSparseArray<PublicKeyHandle> mPublicKeys;
 
     protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
 
-    private final Map<String, PackageSetting> mPackages;
+    private final ArrayMap<String, PackageSetting> mPackages;
 
     private static long lastIssuedKeySetId = 0;
 
     private static long lastIssuedKeyId = 0;
 
-    public KeySetManagerService(Map<String, PackageSetting> packages) {
+    class PublicKeyHandle {
+        private final PublicKey mKey;
+        private final long mId;
+        private int mRefCount;
+
+        public PublicKeyHandle(long id, PublicKey key) {
+            mId = id;
+            mRefCount = 1;
+            mKey = key;
+        }
+
+        /*
+         * Only used when reading state from packages.xml
+         */
+        private PublicKeyHandle(long id, int refCount, PublicKey key) {
+            mId = id;
+            mRefCount = refCount;
+            mKey = key;
+        }
+
+        public long getId() {
+            return mId;
+        }
+
+        public PublicKey getKey() {
+            return mKey;
+        }
+
+        public int getRefCountLPr() {
+            return mRefCount;
+        }
+
+        public void incrRefCountLPw() {
+            mRefCount++;
+            return;
+        }
+        public long decrRefCountLPw() {
+            mRefCount--;
+            return mRefCount;
+        }
+    }
+
+    public KeySetManagerService(ArrayMap<String, PackageSetting> packages) {
         mKeySets = new LongSparseArray<KeySetHandle>();
-        mPublicKeys = new LongSparseArray<PublicKey>();
+        mPublicKeys = new LongSparseArray<PublicKeyHandle>();
         mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
         mPackages = packages;
     }
@@ -92,7 +134,9 @@
         if (id == KEYSET_NOT_FOUND) {
                 return false;
         }
-        return pkg.keySetData.packageIsSignedBy(id);
+        ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
+        ArraySet<Long> testKeys = mKeySetMapping.get(id);
+        return pkgKeys.containsAll(testKeys);
     }
 
     /**
@@ -113,81 +157,45 @@
             || pkg.keySetData.getProperSigningKeySet()
             == PackageKeySetData.KEYSET_UNASSIGNED) {
             throw new NullPointerException("Package has no KeySet data");
-        }
+         }
         long id = getIdByKeySetLPr(ks);
-        return pkg.keySetData.getProperSigningKeySet() == id;
+        if (id == KEYSET_NOT_FOUND) {
+                return false;
+        }
+        ArraySet<Long> pkgKeys = mKeySetMapping.get(pkg.keySetData.getProperSigningKeySet());
+        ArraySet<Long> testKeys = mKeySetMapping.get(id);
+        return pkgKeys.equals(testKeys);
     }
 
     /**
-     * This informs the system that the given package has defined a KeySet
-     * in its manifest that a) contains the given keys and b) is named
-     * alias by that package.
-     */
-    public void addDefinedKeySetToPackageLPw(String packageName,
-            ArraySet<PublicKey> keys, String alias) {
-        if ((packageName == null) || (keys == null) || (alias == null)) {
-            Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
-            return;
-        }
-        PackageSetting pkg = mPackages.get(packageName);
-        if (pkg == null) {
-            throw new NullPointerException("Unknown package");
-        }
-        // Add to KeySets, then to package
-        KeySetHandle ks = addKeySetLPw(keys);
-        long id = getIdByKeySetLPr(ks);
-        pkg.keySetData.addDefinedKeySet(id, alias);
-    }
-
-    /**
-     * This informs the system that the given package has defined a KeySet
-     * alias in its manifest to be an upgradeKeySet.  This must be called
-     * after all of the defined KeySets have been added.
-     */
-    public void addUpgradeKeySetToPackageLPw(String packageName, String alias) {
-        if ((packageName == null) || (alias == null)) {
-            Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
-            return;
-        }
-        PackageSetting pkg = mPackages.get(packageName);
-        if (pkg == null) {
-            throw new NullPointerException("Unknown package");
-        }
-        pkg.keySetData.addUpgradeKeySet(alias);
-    }
-
-    /**
-     * Similar to the above, this informs the system that the given package
-     * was signed by the provided KeySet.
+     * Informs the system that the given package was signed by the provided KeySet.
      */
     public void addSigningKeySetToPackageLPw(String packageName,
             ArraySet<PublicKey> signingKeys) {
-        if ((packageName == null) || (signingKeys == null)) {
-            Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
-            return;
-        }
-        // add the signing KeySet
-        KeySetHandle ks = addKeySetLPw(signingKeys);
-        long id = getIdByKeySetLPr(ks);
-        ArraySet<Long> publicKeyIds = mKeySetMapping.get(id);
-        if (publicKeyIds == null) {
-            throw new NullPointerException("Got invalid KeySet id");
-        }
-        // attach it to the package
+
+        /* check existing keyset for reuse or removal */
         PackageSetting pkg = mPackages.get(packageName);
-        if (pkg == null) {
-            throw new NullPointerException("No such package!");
-        }
-        pkg.keySetData.setProperSigningKeySet(id);
-        // for each KeySet which is a subset of the one above, add the
-        // KeySet id to the package's signing KeySets
-        for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
-            long keySetID = mKeySets.keyAt(keySetIndex);
-            ArraySet<Long> definedKeys = mKeySetMapping.get(keySetID);
-            if (publicKeyIds.containsAll(definedKeys)) {
-                pkg.keySetData.addSigningKeySet(keySetID);
+        long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
+
+        if (signingKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
+            ArraySet<PublicKey> existingKeys = getPublicKeysFromKeySetLPr(signingKeySetId);
+            if (existingKeys.equals(signingKeys)) {
+
+                /* no change in signing keys, leave PackageSetting alone */
+                return;
+            } else {
+
+                /* old keyset no longer valid, remove ref */
+                KeySetHandle ksh = mKeySets.get(signingKeySetId);
+                decrementKeySetLPw(signingKeySetId);
             }
         }
+
+        /* create and add a new keyset */
+        KeySetHandle ks = addKeySetLPw(signingKeys);
+        long id = ks.getId();
+        pkg.keySetData.setProperSigningKeySet(id);
+        return;
     }
 
     /**
@@ -204,25 +212,63 @@
         return KEYSET_NOT_FOUND;
     }
 
-    /**
-     * Fetches the KeySet corresponding to the given stable identifier.
-     *
-     * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
-     * identify a {@link KeySet}.
+    /*
+     * Inform the system that the given package defines the given KeySets.
+     * Remove any KeySets the package no longer defines.
      */
-    public KeySetHandle getKeySetByIdLPr(long id) {
-        return mKeySets.get(id);
+    public void addDefinedKeySetsToPackageLPw(String packageName,
+            ArrayMap<String, ArraySet<PublicKey>> definedMapping) {
+        PackageSetting pkg = mPackages.get(packageName);
+        ArrayMap<String, Long> prevDefinedKeySets = pkg.keySetData.getAliases();
+
+        /* add all of the newly defined KeySets */
+        ArrayMap<String, Long> newKeySetAliases = new ArrayMap<String, Long>();
+        final int defMapSize = definedMapping.size();
+        for (int i = 0; i < defMapSize; i++) {
+            String alias = definedMapping.keyAt(i);
+            ArraySet<PublicKey> pubKeys = definedMapping.valueAt(i);
+            if (alias != null && pubKeys != null && pubKeys.size() > 0) {
+                KeySetHandle ks = addKeySetLPw(pubKeys);
+                newKeySetAliases.put(alias, ks.getId());
+            }
+        }
+
+        /* remove each of the old references */
+        final int prevDefSize = prevDefinedKeySets.size();
+        for (int i = 0; i < prevDefSize; i++) {
+            decrementKeySetLPw(prevDefinedKeySets.valueAt(i));
+        }
+        pkg.keySetData.removeAllUpgradeKeySets();
+
+        /* switch to the just-added */
+        pkg.keySetData.setAliases(newKeySetAliases);
+        return;
     }
 
     /**
-     * Fetches the {@link KeySetHandle} that a given package refers to by the
-     * provided alias. Returns null if the package is unknown or does not have a
+     * This informs the system that the given package has defined a KeySet
+     * alias in its manifest to be an upgradeKeySet.  This must be called
+     * after all of the defined KeySets have been added.
+     */
+    public void addUpgradeKeySetsToPackageLPw(String packageName,
+        ArraySet<String> upgradeAliases) {
+        PackageSetting pkg = mPackages.get(packageName);
+        final int uaSize = upgradeAliases.size();
+        for (int i = 0; i < uaSize; i++) {
+            pkg.keySetData.addUpgradeKeySet(upgradeAliases.valueAt(i));
+        }
+        return;
+    }
+
+    /**
+     * Fetched the {@link KeySetHandle} that a given package refers to by the
+     * provided alias.  Returns null if the package is unknown or does not have a
      * KeySet corresponding to that alias.
      */
     public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
         PackageSetting p = mPackages.get(packageName);
         if (p == null || p.keySetData == null) {
-                return null;
+            return null;
         }
         Long keySetId = p.keySetData.getAliases().get(alias);
         if (keySetId == null) {
@@ -243,8 +289,10 @@
             return null;
         }
         ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
-        for (long pkId : mKeySetMapping.get(id)) {
-            mPubKeys.add(mPublicKeys.get(pkId));
+        ArraySet<Long> pkIds = mKeySetMapping.get(id);
+        final int pkSize = pkIds.size();
+        for (int i = 0; i < pkSize; i++) {
+            mPubKeys.add(mPublicKeys.get(pkIds.valueAt(i)).getKey());
         }
         return mPubKeys;
     }
@@ -254,7 +302,7 @@
      * package.
      *
      * @throws IllegalArgumentException if the package has no keyset data.
-     * @throws NullPointerException if the package is unknown.
+     * @throws NullPointerException if the packgae is unknown.
      */
     public KeySetHandle  getSigningKeySetByPackageNameLPr(String packageName) {
         PackageSetting p = mPackages.get(packageName);
@@ -268,99 +316,100 @@
     }
 
     /**
-     * Fetches all the known {@link KeySetHandle KeySets} that may upgrade the given
-     * package.
-     *
-     * @throws IllegalArgumentException if the package has no keyset data.
-     * @throws NullPointerException if the package is unknown.
-     */
-    public ArraySet<KeySetHandle> getUpgradeKeySetsByPackageNameLPr(String packageName) {
-        ArraySet<KeySetHandle> upgradeKeySets = new ArraySet<KeySetHandle>();
-        PackageSetting p = mPackages.get(packageName);
-        if (p == null) {
-            throw new NullPointerException("Unknown package");
-        }
-        if (p.keySetData == null) {
-            throw new IllegalArgumentException("Package has no keySet data");
-        }
-        if (p.keySetData.isUsingUpgradeKeySets()) {
-            for (long l : p.keySetData.getUpgradeKeySets()) {
-                upgradeKeySets.add(mKeySets.get(l));
-            }
-        }
-        return upgradeKeySets;
-    }
-
-    /**
      * Creates a new KeySet corresponding to the given keys.
      *
      * If the {@link PublicKey PublicKeys} aren't known to the system, this
-     * adds them. Otherwise, they're deduped.
+     * adds them. Otherwise, they're deduped and the reference count
+     * incremented.
      *
      * If the KeySet isn't known to the system, this adds that and creates the
-     * mapping to the PublicKeys. If it is known, then it's deduped.
-     *
-     * If the KeySet isn't known to the system, this adds it to all appropriate
-     * signingKeySets
+     * mapping to the PublicKeys. If it is known, then it's deduped and the
+     * reference count is incremented.
      *
      * Throws if the provided set is {@code null}.
      */
     private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) {
-        if (keys == null) {
-            throw new NullPointerException("Provided keys cannot be null");
+        if (keys == null || keys.size() == 0) {
+            throw new IllegalArgumentException("Cannot add an empty set of keys!");
         }
-        // add each of the keys in the provided set
+
+        /* add each of the keys in the provided set */
         ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
-        for (PublicKey k : keys) {
-            long id = addPublicKeyLPw(k);
+        final int kSize = keys.size();
+        for (int i = 0; i < kSize; i++) {
+            long id = addPublicKeyLPw(keys.valueAt(i));
             addedKeyIds.add(id);
         }
 
-        // check to see if the resulting keyset is new
+        /* check to see if the resulting keyset is new */
         long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
         if (existingKeySetId != KEYSET_NOT_FOUND) {
-            return mKeySets.get(existingKeySetId);
+
+            /* public keys were incremented, but we aren't adding a new keyset: undo */
+            for (int i = 0; i < kSize; i++) {
+                decrementPublicKeyLPw(addedKeyIds.valueAt(i));
+            }
+            KeySetHandle ks = mKeySets.get(existingKeySetId);
+            ks.incrRefCountLPw();
+            return ks;
         }
 
-        // create the KeySet object
-        KeySetHandle ks = new KeySetHandle();
-        // get the first unoccupied slot in mKeySets
+        // get the next keyset id
         long id = getFreeKeySetIDLPw();
-        // add the KeySet object to it
+
+        // create the KeySet object and add to mKeySets and mapping
+        KeySetHandle ks = new KeySetHandle(id);
         mKeySets.put(id, ks);
-        // add the stable key ids to the mapping
         mKeySetMapping.put(id, addedKeyIds);
-        // add this KeySet id to all packages which are signed by it
-        for (String pkgName : mPackages.keySet()) {
-            PackageSetting p = mPackages.get(pkgName);
-            if (p.keySetData != null) {
-                long pProperSigning = p.keySetData.getProperSigningKeySet();
-                if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
-                    ArraySet<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
-                    if (pSigningKeys.containsAll(addedKeyIds)) {
-                        p.keySetData.addSigningKeySet(id);
-                    }
-                }
-            }
-        }
-        // go home
         return ks;
     }
 
+    /*
+     * Decrements the reference to KeySet represented by the given id.  If this
+     * drops to zero, then also decrement the reference to each public key it
+     * contains and remove the KeySet.
+     */
+    private void decrementKeySetLPw(long id) {
+        KeySetHandle ks = mKeySets.get(id);
+        if (ks.decrRefCountLPw() <= 0) {
+            ArraySet<Long> pubKeys = mKeySetMapping.get(id);
+            final int pkSize = pubKeys.size();
+            for (int i = 0; i < pkSize; i++) {
+                decrementPublicKeyLPw(pubKeys.valueAt(i));
+            }
+            mKeySets.delete(id);
+            mKeySetMapping.delete(id);
+        }
+        return;
+    }
+
+    /*
+     * Decrements the reference to PublicKey represented by the given id.  If
+     * this drops to zero, then remove it.
+     */
+    private void decrementPublicKeyLPw(long id) {
+        PublicKeyHandle pk = mPublicKeys.get(id);
+        if (pk.decrRefCountLPw() <= 0) {
+            mPublicKeys.delete(id);
+        }
+        return;
+    }
+
     /**
      * Adds the given PublicKey to the system, deduping as it goes.
      */
     private long addPublicKeyLPw(PublicKey key) {
-        // check if the public key is new
-        long existingKeyId = getIdForPublicKeyLPr(key);
-        if (existingKeyId != PUBLIC_KEY_NOT_FOUND) {
-            return existingKeyId;
+        long id = getIdForPublicKeyLPr(key);
+        if (id != PUBLIC_KEY_NOT_FOUND) {
+
+            /* We already know about this key, increment its ref count and ret */
+            mPublicKeys.get(id).incrRefCountLPw();
+            return id;
         }
-        // if it's new find the first unoccupied slot in the public keys
-        long id = getFreePublicKeyIdLPw();
-        // add the public key to it
-        mPublicKeys.put(id, key);
-        // return the stable identifier
+
+        /* if it's new find the first unoccupied slot in the public keys */
+        id = getFreePublicKeyIdLPw();
+        mPublicKeys.put(id, new PublicKeyHandle(id, key));
         return id;
     }
 
@@ -385,7 +434,7 @@
     private long getIdForPublicKeyLPr(PublicKey k) {
         String encodedPublicKey = new String(k.getEncoded());
         for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
-            PublicKey value = mPublicKeys.valueAt(publicKeyIndex);
+            PublicKey value = mPublicKeys.valueAt(publicKeyIndex).getKey();
             String encodedExistingKey = new String(value.getEncoded());
             if (encodedPublicKey.equals(encodedExistingKey)) {
                 return mPublicKeys.keyAt(publicKeyIndex);
@@ -410,83 +459,32 @@
         return lastIssuedKeyId;
     }
 
+    /*
+     * This package is being removed from the system, so we need to
+     * remove its keyset and public key references, then remove its
+     * keyset data.
+     */
     public void removeAppKeySetDataLPw(String packageName) {
-        // Get the package's known keys and KeySets
-        ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
-        ArraySet<Long> deletableKeys = new ArraySet<Long>();
-        final int origDksSize = deletableKeySets.size();
-        for (int i = 0; i < origDksSize; i++) {
-            ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i));
-            if (knownKeys != null) {
-                deletableKeys.addAll(knownKeys);
-            }
+
+        /* remove refs from common keysets and public keys */
+        PackageSetting pkg = mPackages.get(packageName);
+        long signingKeySetId = pkg.keySetData.getProperSigningKeySet();
+        decrementKeySetLPw(signingKeySetId);
+        ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
+        for (int i = 0; i < definedKeySets.size(); i++) {
+            decrementKeySetLPw(definedKeySets.valueAt(i));
         }
 
-        // Now remove the keys and KeySets on which any other package relies
-        for (String pkgName : mPackages.keySet()) {
-            if (pkgName.equals(packageName)) {
-                continue;
-            }
-            ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
-            deletableKeySets.removeAll(knownKeySets);
-            final int kksSize = knownKeySets.size();
-            for (int i = 0; i < kksSize; i++) {
-                ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i));
-                if (knownKeys != null) {
-                    deletableKeys.removeAll(knownKeys);
-                }
-            }
-        }
-
-        // The remaining keys and KeySets are not relied on by any other
-        // application and so can be safely deleted.
-        final int dksSize = deletableKeySets.size();
-        for (int i = 0; i < dksSize; i++) {
-            Long ks = deletableKeySets.valueAt(i);
-            mKeySets.delete(ks);
-            mKeySetMapping.delete(ks);
-        }
-        final int dkSize = deletableKeys.size();
-        for (int i = 0; i < dkSize; i++) {
-            mPublicKeys.delete(deletableKeys.valueAt(i));
-        }
-
-        // Now remove the deleted KeySets from each package's signingKeySets
-        for (String pkgName : mPackages.keySet()) {
-            PackageSetting p = mPackages.get(pkgName);
-            for (int i = 0; i < dksSize; i++) {
-                Long ks = deletableKeySets.valueAt(i);
-                p.keySetData.removeSigningKeySet(ks);
-            }
-        }
-        // Finally, remove all KeySets from the original package
-        PackageSetting p = mPackages.get(packageName);
-        clearPackageKeySetDataLPw(p);
-    }
-
-    private void clearPackageKeySetDataLPw(PackageSetting p) {
-        p.keySetData.removeAllSigningKeySets();
-        p.keySetData.removeAllUpgradeKeySets();
-        p.keySetData.removeAllDefinedKeySets();
+        /* remove from package */
+        clearPackageKeySetDataLPw(pkg);
         return;
     }
 
-    private ArraySet<Long> getOriginalKeySetsByPackageNameLPr(String packageName) {
-        PackageSetting p = mPackages.get(packageName);
-        if (p == null) {
-            throw new NullPointerException("Unknown package");
-        }
-        if (p.keySetData == null) {
-            throw new IllegalArgumentException("Package has no keySet data");
-        }
-        ArraySet<Long> knownKeySets = new ArraySet<Long>();
-        knownKeySets.add(p.keySetData.getProperSigningKeySet());
-        if (p.keySetData.isUsingDefinedKeySets()) {
-            for (long ks : p.keySetData.getDefinedKeySets()) {
-                knownKeySets.add(ks);
-            }
-        }
-        return knownKeySets;
+    private void clearPackageKeySetDataLPw(PackageSetting pkg) {
+        pkg.keySetData.setProperSigningKeySet(PackageKeySetData.KEYSET_UNASSIGNED);
+        pkg.keySetData.removeAllDefinedKeySets();
+        pkg.keySetData.removeAllUpgradeKeySets();
+        return;
     }
 
     public String encodePublicKey(PublicKey k) throws IOException {
@@ -496,7 +494,7 @@
     public void dumpLPr(PrintWriter pw, String packageName,
                         PackageManagerService.DumpState dumpState) {
         boolean printedHeader = false;
-        for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) {
+        for (ArrayMap.Entry<String, PackageSetting> e : mPackages.entrySet()) {
             String keySetPackage = e.getKey();
             if (packageName != null && !packageName.equals(keySetPackage)) {
                 continue;
@@ -511,7 +509,7 @@
             pw.print("  ["); pw.print(keySetPackage); pw.println("]");
             if (pkg.keySetData != null) {
                 boolean printedLabel = false;
-                for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
+                for (ArrayMap.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
                     if (!printedLabel) {
                         pw.print("      KeySets Aliases: ");
                         printedLabel = true;
@@ -527,36 +525,26 @@
                 }
                 printedLabel = false;
                 if (pkg.keySetData.isUsingDefinedKeySets()) {
-                    for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
+                    ArrayMap<String, Long> definedKeySets = pkg.keySetData.getAliases();
+                    final int dksSize = definedKeySets.size();
+                    for (int i = 0; i < dksSize; i++) {
                         if (!printedLabel) {
                             pw.print("      Defined KeySets: ");
                             printedLabel = true;
                         } else {
                             pw.print(", ");
                         }
-                        pw.print(Long.toString(keySetId));
+                        pw.print(Long.toString(definedKeySets.valueAt(i)));
                     }
                 }
                 if (printedLabel) {
                     pw.println("");
                 }
                 printedLabel = false;
-                final long[] signingKeySets = pkg.keySetData.getSigningKeySets();
-                if (signingKeySets != null) {
-                    for (long keySetId : signingKeySets) {
-                        if (!printedLabel) {
-                            pw.print("      Signing KeySets: ");
-                            printedLabel = true;
-                        } else {
-                            pw.print(", ");
-                        }
-                        pw.print(Long.toString(keySetId));
-                    }
-                }
-                if (printedLabel) {
-                    pw.println("");
-                }
-                printedLabel = false;
+                final long signingKeySet = pkg.keySetData.getProperSigningKeySet();
+                pw.print("      Signing KeySets: ");
+                pw.print(Long.toString(signingKeySet));
+                pw.println("");
                 if (pkg.keySetData.isUsingUpgradeKeySets()) {
                     for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
                         if (!printedLabel) {
@@ -593,8 +581,8 @@
         serializer.startTag(null, "keys");
         for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
             long id = mPublicKeys.keyAt(pKeyIndex);
-            PublicKey key = mPublicKeys.valueAt(pKeyIndex);
-            String encodedKey = encodePublicKey(key);
+            PublicKeyHandle pkh = mPublicKeys.valueAt(pKeyIndex);
+            String encodedKey = encodePublicKey(pkh.getKey());
             serializer.startTag(null, "public-key");
             serializer.attribute(null, "identifier", Long.toString(id));
             serializer.attribute(null, "value", encodedKey);
@@ -620,17 +608,17 @@
         serializer.endTag(null, "keysets");
     }
 
-    void readKeySetsLPw(XmlPullParser parser)
+    void readKeySetsLPw(XmlPullParser parser, ArrayMap<Long, Integer> keySetRefCounts)
             throws XmlPullParserException, IOException {
         int type;
         long currentKeySetId = 0;
         int outerDepth = parser.getDepth();
-        String recordedVersion = parser.getAttributeValue(null, "version");
-        if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
+        String recordedVersionStr = parser.getAttributeValue(null, "version");
+        if (recordedVersionStr == null) {
+            // The keyset information comes from pre-versioned devices, and
+            // is inaccurate, don't collect any of it.
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                // Our version is different than the one which generated the old keyset data.
-                // We don't want any of the old data, but we must advance the parser
                 continue;
             }
             // The KeySet information read previously from packages.xml is invalid.
@@ -640,6 +628,7 @@
             }
             return;
         }
+        int recordedVersion = Integer.parseInt(recordedVersionStr);
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -656,6 +645,8 @@
                 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
             }
         }
+
+        addRefCountsFromSavedPackagesLPw(keySetRefCounts);
     }
 
     void readKeysLPw(XmlPullParser parser)
@@ -686,29 +677,49 @@
             }
             final String tagName = parser.getName();
             if (tagName.equals("keyset")) {
-                currentKeySetId = readIdentifierLPw(parser);
-                mKeySets.put(currentKeySetId, new KeySetHandle());
+                String encodedID = parser.getAttributeValue(null, "identifier");
+                currentKeySetId = Long.parseLong(encodedID);
+                int refCount = 0;
+                mKeySets.put(currentKeySetId, new KeySetHandle(currentKeySetId, refCount));
                 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
             } else if (tagName.equals("key-id")) {
-                long id = readIdentifierLPw(parser);
+                String encodedID = parser.getAttributeValue(null, "identifier");
+                long id = Long.parseLong(encodedID);
                 mKeySetMapping.get(currentKeySetId).add(id);
             }
         }
     }
 
-    long readIdentifierLPw(XmlPullParser parser)
-            throws XmlPullParserException {
-        return Long.parseLong(parser.getAttributeValue(null, "identifier"));
-    }
-
     void readPublicKeyLPw(XmlPullParser parser)
             throws XmlPullParserException {
         String encodedID = parser.getAttributeValue(null, "identifier");
         long identifier = Long.parseLong(encodedID);
+        int refCount = 0;
         String encodedPublicKey = parser.getAttributeValue(null, "value");
         PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
         if (pub != null) {
-            mPublicKeys.put(identifier, pub);
+            PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
+            mPublicKeys.put(identifier, pkh);
+        }
+    }
+
+    /*
+     * Set each KeySet ref count.  Also increment all public keys in each keyset.
+     */
+    private void addRefCountsFromSavedPackagesLPw(ArrayMap<Long, Integer> keySetRefCounts) {
+        final int numRefCounts = keySetRefCounts.size();
+        for (int i = 0; i < numRefCounts; i++) {
+            KeySetHandle ks = mKeySets.get(keySetRefCounts.keyAt(i));
+            ks.setRefCountLPw(keySetRefCounts.valueAt(i));
+        }
+
+        final int numKeySets = mKeySets.size();
+        for (int i = 0; i < numKeySets; i++) {
+            ArraySet<Long> pubKeys = mKeySetMapping.valueAt(i);
+            final int pkSize = pubKeys.size();
+            for (int j = 0; j < pkSize; j++) {
+                mPublicKeys.get(pubKeys.valueAt(j)).incrRefCountLPw();
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2dbce0a..4c36fa6 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.annotation.Nullable;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.os.UserHandle;
@@ -23,6 +24,7 @@
 import android.util.Log;
 import android.util.Slog;
 
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -38,7 +40,9 @@
  * Helper class for running dexopt command on packages.
  */
 final class PackageDexOptimizer {
-    static final String TAG = "PackageManager.DexOptimizer";
+    private static final String TAG = "PackageManager.DexOptimizer";
+    static final String OAT_DIR_NAME = "oat";
+    // TODO b/19550105 Remove error codes and use exceptions
     static final int DEX_OPT_SKIPPED = 0;
     static final int DEX_OPT_PERFORMED = 1;
     static final int DEX_OPT_DEFERRED = 2;
@@ -109,52 +113,47 @@
 
             for (String path : paths) {
                 try {
-                    // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
-                    // package or the one we find does not match the image checksum (i.e. it was
-                    // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
-                    // odex file and it matches the checksum of the image but not its base address,
-                    // meaning we need to move it.
-                    final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
-                            pkg.packageName, dexCodeInstructionSet, defer);
-                    if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
-                        Log.i(TAG, "Running dexopt on: " + path + " pkg="
+                    final int dexoptNeeded;
+                    if (forceDex) {
+                        dexoptNeeded = DexFile.DEX2OAT_NEEDED;
+                    } else {
+                        dexoptNeeded = DexFile.getDexOptNeeded(path,
+                                pkg.packageName, dexCodeInstructionSet, defer);
+                    }
+
+                    if (!forceDex && defer && dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+                        // We're deciding to defer a needed dexopt. Don't bother dexopting for other
+                        // paths and instruction sets. We'll deal with them all together when we process
+                        // our list of deferred dexopts.
+                        addPackageForDeferredDexopt(pkg);
+                        return DEX_OPT_DEFERRED;
+                    }
+
+                    if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+                        final String dexoptType;
+                        String oatDir = null;
+                        if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
+                            dexoptType = "dex2oat";
+                            oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
+                        } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
+                            dexoptType = "patchoat";
+                        } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
+                            dexoptType = "self patchoat";
+                        } else {
+                            throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+                        }
+                        Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
                                 + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
-                                + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable);
+                                + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
+                                + " oatDir = " + oatDir);
                         final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
                         final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
                                 !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
-                                vmSafeMode, debuggable);
-
+                                dexoptNeeded, vmSafeMode, debuggable, oatDir);
                         if (ret < 0) {
-                            // Don't bother running dexopt again if we failed, it will probably
-                            // just result in an error again. Also, don't bother dexopting for other
-                            // paths & ISAs.
                             return DEX_OPT_FAILED;
                         }
-
                         performedDexOpt = true;
-                    } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
-                        Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
-                        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
-                        final int ret = mPackageManagerService.mInstaller.patchoat(path, sharedGid,
-                                !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet);
-
-                        if (ret < 0) {
-                            // Don't bother running patchoat again if we failed, it will probably
-                            // just result in an error again. Also, don't bother dexopting for other
-                            // paths & ISAs.
-                            return DEX_OPT_FAILED;
-                        }
-
-                        performedDexOpt = true;
-                    }
-
-                    // We're deciding to defer a needed dexopt. Don't bother dexopting for other
-                    // paths and instruction sets. We'll deal with them all together when we process
-                    // our list of deferred dexopts.
-                    if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
-                        addPackageForDeferredDexopt(pkg);
-                        return DEX_OPT_DEFERRED;
                     }
                 } catch (FileNotFoundException e) {
                     Slog.w(TAG, "Apk not found for dexopt: " + path);
@@ -172,7 +171,7 @@
             }
 
             // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
-            // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+            // either have either succeeded dexopt, or have had getDexOptNeeded tell us
             // it isn't required. We therefore mark that this package doesn't need dexopt unless
             // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
             // it.
@@ -186,6 +185,37 @@
         return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
     }
 
+    /**
+     * Creates oat dir for the specified package. In certain cases oat directory
+     * <strong>cannot</strong> be created:
+     * <ul>
+     *      <li>{@code pkg} is a system app, which is not updated.</li>
+     *      <li>Package location is not a directory, i.e. monolithic install.</li>
+     * </ul>
+     *
+     * @return Absolute path to the oat directory or null, if oat directory
+     * cannot be created.
+     */
+    @Nullable
+    private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)
+            throws IOException {
+        if (pkg.isSystemApp() && !pkg.isUpdatedSystemApp()) {
+            return null;
+        }
+        File codePath = new File(pkg.codePath);
+        if (codePath.isDirectory()) {
+            File oatDir = getOatDir(codePath);
+            mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
+                    dexInstructionSet);
+            return oatDir.getAbsolutePath();
+        }
+        return null;
+    }
+
+    static File getOatDir(File codePath) {
+        return new File(codePath, OAT_DIR_NAME);
+    }
+
     private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
             boolean forceDex, boolean defer, ArraySet<String> done) {
         for (String libName : libs) {
@@ -209,7 +239,7 @@
 
     public void addPackageForDeferredDexopt(PackageParser.Package pkg) {
         if (mDeferredDexOpt == null) {
-            mDeferredDexOpt = new ArraySet<PackageParser.Package>();
+            mDeferredDexOpt = new ArraySet<>();
         }
         mDeferredDexOpt.add(pkg);
     }
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 2150e9a..89fa320 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -30,17 +30,24 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.Manifest;
 import android.app.ActivityManager;
+import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.Notification;
+import android.app.NotificationManager;
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.content.IntentSender.SendIntentException;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageInstaller;
 import android.content.pm.IPackageInstallerCallback;
 import android.content.pm.IPackageInstallerSession;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
@@ -53,7 +60,6 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -64,6 +70,8 @@
 import android.os.SELinux;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
 import android.system.ErrnoException;
 import android.system.Os;
 import android.text.TextUtils;
@@ -76,15 +84,17 @@
 import android.util.SparseBooleanArray;
 import android.util.Xml;
 
+import libcore.io.IoUtils;
+
+import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageHelper;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.ImageUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.IoThread;
 import com.google.android.collect.Sets;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -132,6 +142,7 @@
     private static final String ATTR_ORIGINATING_URI = "originatingUri";
     private static final String ATTR_REFERRER_URI = "referrerUri";
     private static final String ATTR_ABI_OVERRIDE = "abiOverride";
+    private static final String ATTR_VOLUME_UUID = "volumeUuid";
 
     /** Automatically destroy sessions older than this */
     private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
@@ -142,9 +153,10 @@
 
     private final Context mContext;
     private final PackageManagerService mPm;
-    private final AppOpsManager mAppOps;
 
-    private final File mStagingDir;
+    private AppOpsManager mAppOps;
+    private StorageManager mStorage;
+
     private final HandlerThread mInstallThread;
     private final Handler mInstallHandler;
 
@@ -187,12 +199,9 @@
         }
     };
 
-    public PackageInstallerService(Context context, PackageManagerService pm, File stagingDir) {
+    public PackageInstallerService(Context context, PackageManagerService pm) {
         mContext = context;
         mPm = pm;
-        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
-
-        mStagingDir = stagingDir;
 
         mInstallThread = new HandlerThread(TAG);
         mInstallThread.start();
@@ -209,8 +218,9 @@
         synchronized (mSessions) {
             readSessionsLocked();
 
+            final File internalStagingDir = buildInternalStagingDir();
             final ArraySet<File> unclaimedStages = Sets.newArraySet(
-                    mStagingDir.listFiles(sStageFilter));
+                    internalStagingDir.listFiles(sStageFilter));
             final ArraySet<File> unclaimedIcons = Sets.newArraySet(
                     mSessionsDir.listFiles());
 
@@ -225,9 +235,10 @@
             for (File stage : unclaimedStages) {
                 Slog.w(TAG, "Deleting orphan stage " + stage);
                 if (stage.isDirectory()) {
-                    FileUtils.deleteContents(stage);
+                    mPm.mInstaller.rmPackageDir(stage.getAbsolutePath());
+                } else {
+                    stage.delete();
                 }
-                stage.delete();
             }
 
             // Clean up orphaned icons
@@ -238,6 +249,11 @@
         }
     }
 
+    public void systemReady() {
+        mAppOps = mContext.getSystemService(AppOpsManager.class);
+        mStorage = mContext.getSystemService(StorageManager.class);
+    }
+
     public void onSecureContainersAvailable() {
         synchronized (mSessions) {
             final ArraySet<String> unclaimed = new ArraySet<>();
@@ -275,13 +291,13 @@
     }
 
     @Deprecated
-    public File allocateInternalStageDirLegacy() throws IOException {
+    public File allocateStageDirLegacy(String volumeUuid) throws IOException {
         synchronized (mSessions) {
             try {
                 final int sessionId = allocateSessionIdLocked();
                 mLegacySessions.put(sessionId, true);
-                final File stageDir = buildInternalStageDir(sessionId);
-                prepareInternalStageDir(stageDir);
+                final File stageDir = buildStageDir(volumeUuid, sessionId);
+                prepareStageDir(stageDir);
                 return stageDir;
             } catch (IllegalStateException e) {
                 throw new IOException(e);
@@ -322,11 +338,6 @@
                             Slog.w(TAG, "Abandoning old session first created at "
                                     + session.createdMillis);
                             valid = false;
-                        } else if (session.stageDir != null
-                                && !session.stageDir.exists()) {
-                            Slog.w(TAG, "Abandoning internal session with missing stage "
-                                    + session.stageDir);
-                            valid = false;
                         } else {
                             valid = true;
                         }
@@ -378,6 +389,7 @@
         params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
         params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
         params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
+        params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
 
         final File appIconFile = buildAppIconFile(sessionId);
         if (appIconFile.exists()) {
@@ -448,6 +460,7 @@
         writeUriAttribute(out, ATTR_ORIGINATING_URI, params.originatingUri);
         writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
         writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
+        writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
 
         // Persist app icon if changed since last written
         final File appIconFile = buildAppIconFile(session.sessionId);
@@ -516,6 +529,15 @@
             params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
         }
 
+        // Only system components can circumvent runtime permissions when installing.
+        if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
+                && mContext.checkCallingOrSelfPermission(Manifest.permission
+                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException("You need the "
+                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
+        }
+
         // Defensively resize giant app icons
         if (params.appIcon != null) {
             final ActivityManager am = (ActivityManager) mContext.getSystemService(
@@ -528,28 +550,40 @@
             }
         }
 
-        if (params.mode == SessionParams.MODE_FULL_INSTALL
-                || params.mode == SessionParams.MODE_INHERIT_EXISTING) {
+        switch (params.mode) {
+            case SessionParams.MODE_FULL_INSTALL:
+            case SessionParams.MODE_INHERIT_EXISTING:
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid install mode: " + params.mode);
+        }
+
+        // If caller requested explicit location, sanity check it, otherwise
+        // resolve the best internal or adopted location.
+        if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
+            if (!PackageHelper.fitsOnInternal(mContext, params.sizeBytes)) {
+                throw new IOException("No suitable internal storage available");
+            }
+
+        } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
+            if (!PackageHelper.fitsOnExternal(mContext, params.sizeBytes)) {
+                throw new IOException("No suitable external storage available");
+            }
+
+        } else {
+            // For now, installs to adopted media are treated as internal from
+            // an install flag point-of-view.
+            params.setInstallFlagsInternal();
+
             // Resolve best location for install, based on combination of
             // requested install flags, delta size, and manifest settings.
             final long ident = Binder.clearCallingIdentity();
             try {
-                final int resolved = PackageHelper.resolveInstallLocation(mContext,
-                        params.appPackageName, params.installLocation, params.sizeBytes,
-                        params.installFlags);
-
-                if (resolved == PackageHelper.RECOMMEND_INSTALL_INTERNAL) {
-                    params.setInstallFlagsInternal();
-                } else if (resolved == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
-                    params.setInstallFlagsExternal();
-                } else {
-                    throw new IOException("No storage with enough free space; res=" + resolved);
-                }
+                params.volumeUuid = PackageHelper.resolveInstallVolume(mContext,
+                        params.appPackageName, params.installLocation, params.sizeBytes);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-        } else {
-            throw new IllegalArgumentException("Invalid install mode: " + params.mode);
         }
 
         final int sessionId;
@@ -574,7 +608,7 @@
             File stageDir = null;
             String stageCid = null;
             if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
-                stageDir = buildInternalStageDir(sessionId);
+                stageDir = buildStageDir(params.volumeUuid, sessionId);
             } else {
                 stageCid = buildExternalStageCid(sessionId);
             }
@@ -673,11 +707,30 @@
         throw new IllegalStateException("Failed to allocate session ID");
     }
 
-    private File buildInternalStageDir(int sessionId) {
-        return new File(mStagingDir, "vmdl" + sessionId + ".tmp");
+    private File buildInternalStagingDir() {
+        return new File(Environment.getDataDirectory(), "app");
     }
 
-    static void prepareInternalStageDir(File stageDir) throws IOException {
+    private File buildStagingDir(String volumeUuid) throws FileNotFoundException {
+        if (volumeUuid == null) {
+            return buildInternalStagingDir();
+        } else {
+            final VolumeInfo vol = mStorage.findVolumeByUuid(volumeUuid);
+            if (vol != null && vol.type == VolumeInfo.TYPE_PRIVATE
+                    && vol.state == VolumeInfo.STATE_MOUNTED) {
+                return new File(vol.path, "app");
+            } else {
+                throw new FileNotFoundException("Failed to find volume for UUID " + volumeUuid);
+            }
+        }
+    }
+
+    private File buildStageDir(String volumeUuid, int sessionId) throws FileNotFoundException {
+        final File stagingDir = buildStagingDir(volumeUuid);
+        return new File(stagingDir, "vmdl" + sessionId + ".tmp");
+    }
+
+    static void prepareStageDir(File stageDir) throws IOException {
         if (stageDir.exists()) {
             throw new IOException("Session dir already exists: " + stageDir);
         }
@@ -749,16 +802,34 @@
     }
 
     @Override
-    public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) {
-        mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true, "uninstall");
+    public void uninstall(String packageName, String callerPackageName, int flags,
+                IntentSender statusReceiver, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
+        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
+            mAppOps.checkPackage(callingUid, callerPackageName);
+        }
+
+        // Check whether the caller is device owner
+        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(callerPackageName);
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
-                statusReceiver, packageName);
+                statusReceiver, packageName, isDeviceOwner, userId);
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
                 == PackageManager.PERMISSION_GRANTED) {
             // Sweet, call straight through!
             mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
-
+        } else if (isDeviceOwner) {
+            // Allow the DeviceOwner to silently delete packages
+            // Need to clear the calling identity to get DELETE_PACKAGES permission
+            long ident = Binder.clearCallingIdentity();
+            try {
+                mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         } else {
             // Take a short detour to confirm with user
             final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
@@ -814,12 +885,21 @@
         private final Context mContext;
         private final IntentSender mTarget;
         private final String mPackageName;
+        private final Notification mNotification;
 
         public PackageDeleteObserverAdapter(Context context, IntentSender target,
-                String packageName) {
+                String packageName, boolean showNotification, int userId) {
             mContext = context;
             mTarget = target;
             mPackageName = packageName;
+            if (showNotification) {
+                mNotification = buildSuccessNotification(mContext,
+                        mContext.getResources().getString(R.string.package_deleted_device_owner),
+                        packageName,
+                        userId);
+            } else {
+                mNotification = null;
+            }
         }
 
         @Override
@@ -837,6 +917,11 @@
 
         @Override
         public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+            if (PackageManager.DELETE_SUCCEEDED == returnCode && mNotification != null) {
+                NotificationManager notificationManager = (NotificationManager)
+                        mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                notificationManager.notify(basePackageName, 0, mNotification);
+            }
             final Intent fillIn = new Intent();
             fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);
             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
@@ -855,11 +940,16 @@
         private final Context mContext;
         private final IntentSender mTarget;
         private final int mSessionId;
+        private final boolean mShowNotification;
+        private final int mUserId;
 
-        public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId) {
+        public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
+                boolean showNotification, int userId) {
             mContext = context;
             mTarget = target;
             mSessionId = sessionId;
+            mShowNotification = showNotification;
+            mUserId = userId;
         }
 
         @Override
@@ -878,6 +968,17 @@
         @Override
         public void onPackageInstalled(String basePackageName, int returnCode, String msg,
                 Bundle extras) {
+            if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
+                Notification notification = buildSuccessNotification(mContext,
+                        mContext.getResources().getString(R.string.package_installed_device_owner),
+                        basePackageName,
+                        mUserId);
+                if (notification != null) {
+                    NotificationManager notificationManager = (NotificationManager)
+                            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                    notificationManager.notify(basePackageName, 0, notification);
+                }
+            }
             final Intent fillIn = new Intent();
             fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
             fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
@@ -899,6 +1000,40 @@
         }
     }
 
+    /**
+     * Build a notification for package installation / deletion by device owners that is shown if
+     * the operation succeeds.
+     */
+    private static Notification buildSuccessNotification(Context context, String contentText,
+            String basePackageName, int userId) {
+        PackageInfo packageInfo = null;
+        try {
+            packageInfo = AppGlobals.getPackageManager().getPackageInfo(
+                    basePackageName, 0, userId);
+        } catch (RemoteException ignored) {
+        }
+        if (packageInfo == null || packageInfo.applicationInfo == null) {
+            Slog.w(TAG, "Notification not built for package: " + basePackageName);
+            return null;
+        }
+        PackageManager pm = context.getPackageManager();
+        Bitmap packageIcon = ImageUtils.buildScaledBitmap(
+                packageInfo.applicationInfo.loadIcon(pm),
+                context.getResources().getDimensionPixelSize(
+                        android.R.dimen.notification_large_icon_width),
+                context.getResources().getDimensionPixelSize(
+                        android.R.dimen.notification_large_icon_height));
+        CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
+        return new Notification.Builder(context)
+                .setSmallIcon(R.drawable.ic_check_circle_24px)
+                .setColor(context.getResources().getColor(
+                        R.color.system_notification_accent_color))
+                .setContentTitle(packageLabel)
+                .setContentText(contentText)
+                .setLargeIcon(packageIcon)
+                .build();
+    }
+
     private static class Callbacks extends Handler {
         private static final int MSG_SESSION_CREATED = 1;
         private static final int MSG_SESSION_BADGING_CHANGED = 2;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index cc1b3ad..46db2d8 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -25,8 +25,9 @@
 import static android.system.OsConstants.O_RDONLY;
 import static android.system.OsConstants.O_WRONLY;
 import static com.android.server.pm.PackageInstallerService.prepareExternalStageCid;
-import static com.android.server.pm.PackageInstallerService.prepareInternalStageDir;
+import static com.android.server.pm.PackageInstallerService.prepareStageDir;
 
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -61,6 +62,9 @@
 import android.util.MathUtils;
 import android.util.Slog;
 
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.content.PackageHelper;
@@ -69,9 +73,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 
-import libcore.io.IoUtils;
-import libcore.io.Libcore;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -92,6 +93,7 @@
     private final Context mContext;
     private final PackageManagerService mPm;
     private final Handler mHandler;
+    private final boolean mIsInstallerDeviceOwner;
 
     final int sessionId;
     final int userId;
@@ -208,8 +210,15 @@
         mPrepared = prepared;
         mSealed = sealed;
 
+        // Device owners are allowed to silently install packages, so the permission check is
+        // waived if the installer is the device owner.
+        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        mIsInstallerDeviceOwner = (dpm != null) && dpm.isDeviceOwnerApp(installerPackageName);
         if ((mPm.checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
-                == PackageManager.PERMISSION_GRANTED) || (installerUid == Process.ROOT_UID)) {
+                == PackageManager.PERMISSION_GRANTED)
+                || (installerUid == Process.ROOT_UID)
+                || mIsInstallerDeviceOwner) {
             mPermissionsAccepted = true;
         } else {
             mPermissionsAccepted = false;
@@ -440,7 +449,7 @@
         mActiveCount.incrementAndGet();
 
         final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
-                statusReceiver, sessionId);
+                statusReceiver, sessionId, mIsInstallerDeviceOwner, userId);
         mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
     }
 
@@ -892,7 +901,7 @@
         synchronized (mLock) {
             if (!mPrepared) {
                 if (stageDir != null) {
-                    prepareInternalStageDir(stageDir);
+                    prepareStageDir(stageDir);
                 } else if (stageCid != null) {
                     prepareExternalStageCid(stageCid, params.sizeBytes);
 
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index 8f12c03..a9126c0 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -27,12 +27,8 @@
     /* KeySet containing all signing keys - superset of the others */
     private long mProperSigningKeySet;
 
-    private long[] mSigningKeySets;
-
     private long[] mUpgradeKeySets;
 
-    private long[] mDefinedKeySets;
-
     private final ArrayMap<String, Long> mKeySetAliases = new ArrayMap<String, Long>();
 
     PackageKeySetData() {
@@ -41,23 +37,12 @@
 
     PackageKeySetData(PackageKeySetData original) {
         mProperSigningKeySet = original.mProperSigningKeySet;
-        mSigningKeySets = ArrayUtils.cloneOrNull(original.mSigningKeySets);
         mUpgradeKeySets = ArrayUtils.cloneOrNull(original.mUpgradeKeySets);
-        mDefinedKeySets = ArrayUtils.cloneOrNull(original.mDefinedKeySets);
         mKeySetAliases.putAll(original.mKeySetAliases);
     }
 
     protected void setProperSigningKeySet(long ks) {
-        if (ks == mProperSigningKeySet) {
-
-            /* nothing to change */
-            return;
-        }
-
-        /* otherwise, our current signing keysets are likely invalid */
-        removeAllSigningKeySets();
         mProperSigningKeySet = ks;
-        addSigningKeySet(ks);
         return;
     }
 
@@ -65,15 +50,10 @@
         return mProperSigningKeySet;
     }
 
-    protected void addSigningKeySet(long ks) {
-        mSigningKeySets = ArrayUtils.appendLong(mSigningKeySets, ks);
-    }
-
-    protected void removeSigningKeySet(long ks) {
-        mSigningKeySets = ArrayUtils.removeLong(mSigningKeySets, ks);
-    }
-
     protected void addUpgradeKeySet(String alias) {
+        if (alias == null) {
+            return;
+        }
 
         /* must have previously been defined */
         Long ks = mKeySetAliases.get(alias);
@@ -89,19 +69,9 @@
      * Used only when restoring keyset data from persistent storage.  Must
      * correspond to a defined-keyset.
      */
+
     protected void addUpgradeKeySetById(long ks) {
-        mSigningKeySets = ArrayUtils.appendLong(mSigningKeySets, ks);
-    }
-
-    protected void addDefinedKeySet(long ks, String alias) {
-        mDefinedKeySets = ArrayUtils.appendLong(mDefinedKeySets, ks);
-        mKeySetAliases.put(alias, ks);
-    }
-
-    protected void removeAllSigningKeySets() {
-        mProperSigningKeySet = KEYSET_UNASSIGNED;
-        mSigningKeySets = null;
-        return;
+        mUpgradeKeySets = ArrayUtils.appendLong(mUpgradeKeySets, ks);
     }
 
     protected void removeAllUpgradeKeySets() {
@@ -109,36 +79,44 @@
         return;
     }
 
-    protected void removeAllDefinedKeySets() {
-        mDefinedKeySets = null;
-        mKeySetAliases.clear();
-        return;
-    }
-
-    protected boolean packageIsSignedBy(long ks) {
-        return ArrayUtils.contains(mSigningKeySets, ks);
-    }
-
-    protected long[] getSigningKeySets() {
-        return mSigningKeySets;
-    }
-
     protected long[] getUpgradeKeySets() {
         return mUpgradeKeySets;
     }
 
-    protected long[] getDefinedKeySets() {
-        return mDefinedKeySets;
-    }
-
     protected ArrayMap<String, Long> getAliases() {
         return mKeySetAliases;
     }
 
+    /*
+     * Replace defined keysets with new ones.
+     */
+    protected void setAliases(ArrayMap<String, Long> newAliases) {
+
+        /* remove old aliases */
+        removeAllDefinedKeySets();
+
+        /* add new ones */
+        final int newAliasSize = newAliases.size();
+        for (int i = 0; i < newAliasSize; i++) {
+            mKeySetAliases.put(newAliases.keyAt(i), newAliases.valueAt(i));;
+        }
+    }
+
+    protected void addDefinedKeySet(long ks, String alias) {
+        mKeySetAliases.put(alias, ks);
+    }
+
+    protected void removeAllDefinedKeySets() {
+        final int aliasSize = mKeySetAliases.size();
+        for (int i = 0; i < aliasSize; i++) {
+            mKeySetAliases.removeAt(i);
+        }
+    }
+
     protected boolean isUsingDefinedKeySets() {
 
-        /* should never be the case that mDefinedKeySets.length == 0 */
-        return (mDefinedKeySets != null && mDefinedKeySets.length > 0);
+        /* should never be the case that mUpgradeKeySets.length == 0 */
+        return (mKeySetAliases.size() > 0);
     }
 
     protected boolean isUsingUpgradeKeySets() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b9dfc21..a0313e7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -43,11 +43,17 @@
 import static android.content.pm.PackageManager.INSTALL_FAILED_USER_RESTRICTED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
 import static android.content.pm.PackageManager.INSTALL_FORWARD_LOCK;
+import static android.content.pm.PackageManager.INSTALL_INTERNAL;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.MOVE_EXTERNAL_MEDIA;
+import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST;
+import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING;
+import static android.content.pm.PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
+import static android.content.pm.PackageManager.MOVE_INTERNAL;
 import static android.content.pm.PackageParser.isApkFile;
 import static android.os.Process.PACKAGE_INFO_GID;
 import static android.os.Process.SYSTEM_UID;
@@ -62,32 +68,10 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
+import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
 
 import android.Manifest;
-import android.content.pm.IntentFilterVerificationInfo;
-import android.util.ArrayMap;
-
-import com.android.internal.R;
-import com.android.internal.app.IMediaContainerService;
-import com.android.internal.app.ResolverActivity;
-import com.android.internal.content.NativeLibraryHelper;
-import com.android.internal.content.PackageHelper;
-import com.android.internal.os.IParcelFileDescriptorFactory;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.EventLogTags;
-import com.android.server.IntentResolver;
-import com.android.server.LocalServices;
-import com.android.server.ServiceThread;
-import com.android.server.SystemConfig;
-import com.android.server.Watchdog;
-import com.android.server.pm.Settings.DatabaseVersion;
-import com.android.server.storage.DeviceStorageMonitorInternal;
-
-import org.xmlpull.v1.XmlSerializer;
-
+import org.xmlpull.v1.XmlPullParser;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -117,6 +101,7 @@
 import android.content.pm.IPackageMoveObserver;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
 import android.content.pm.ManifestDigest;
 import android.content.pm.PackageCleanItem;
@@ -125,10 +110,10 @@
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
+import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.ActivityIntentInfo;
 import android.content.pm.PackageParser.PackageLite;
 import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
 import android.content.pm.ParceledListSlice;
@@ -148,11 +133,9 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Environment;
 import android.os.Environment.UserEnvironment;
-import android.os.storage.IMountService;
-import android.os.storage.StorageManager;
-import android.os.Debug;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -168,6 +151,10 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.IMountService;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
 import android.security.KeyStore;
 import android.security.SystemKeyStore;
 import android.system.ErrnoException;
@@ -175,6 +162,7 @@
 import android.system.StructStat;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.DisplayMetrics;
@@ -186,11 +174,41 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.Xml;
 import android.view.Display;
 
+import dalvik.system.DexFile;
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
+
+import com.android.internal.R;
+import com.android.internal.app.IMediaContainerService;
+import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.PackageHelper;
+import com.android.internal.os.IParcelFileDescriptorFactory;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.EventLogTags;
+import com.android.server.IntentResolver;
+import com.android.server.LocalServices;
+import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
+import com.android.server.Watchdog;
+import com.android.server.pm.Settings.DatabaseVersion;
+import com.android.server.storage.DeviceStorageMonitorInternal;
+
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
@@ -220,12 +238,6 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-
-import libcore.io.IoUtils;
-import libcore.util.EmptyArray;
-
 /**
  * Keep track of all those .apks everywhere.
  * 
@@ -243,6 +255,7 @@
     static final boolean DEBUG_SETTINGS = false;
     static final boolean DEBUG_PREFERRED = false;
     static final boolean DEBUG_UPGRADE = false;
+    private static final boolean DEBUG_BACKUP = true;
     private static final boolean DEBUG_INSTALL = false;
     private static final boolean DEBUG_REMOVE = false;
     private static final boolean DEBUG_BROADCASTS = false;
@@ -254,8 +267,7 @@
     private static final boolean DEBUG_DEXOPT = false;
     private static final boolean DEBUG_ABI_SELECTION = false;
 
-    static final boolean RUNTIME_PERMISSIONS_ENABLED =
-            SystemProperties.getInt("ro.runtime.permissions.enabled", 0) == 1;
+    static final boolean RUNTIME_PERMISSIONS_ENABLED = true;
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -548,19 +560,18 @@
                         mIntentFilterVerificationStates.get(verificationId);
 
                 String packageName = ivs.getPackageName();
-                boolean modified = false;
 
                 ArrayList<PackageParser.ActivityIntentInfo> filters = ivs.getFilters();
                 final int filterCount = filters.size();
+                ArraySet<String> domainsSet = new ArraySet<>();
                 for (int m=0; m<filterCount; m++) {
                     PackageParser.ActivityIntentInfo filter = filters.get(m);
-                    synchronized (mPackages) {
-                        modified = mSettings.createIntentFilterVerificationIfNeededLPw(
-                                packageName, filter.getHosts());
-                    }
+                    domainsSet.addAll(filter.getHostsList());
                 }
+                ArrayList<String> domainsList = new ArrayList<>(domainsSet);
                 synchronized (mPackages) {
-                    if (modified) {
+                    if (mSettings.createIntentFilterVerificationIfNeededLPw(
+                            packageName, domainsList) != null) {
                         scheduleWriteSettingsLocked();
                     }
                 }
@@ -570,7 +581,7 @@
         }
 
         private void sendVerificationRequest(int userId, int verificationId,
-                                             IntentFilterVerificationState ivs) {
+                IntentFilterVerificationState ivs) {
 
             Intent verificationIntent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
             verificationIntent.putExtra(
@@ -621,7 +632,7 @@
                         + verificationId + " packageName:" + packageName);
                 return;
             }
-            Slog.d(TAG, "Updating IntentFilterVerificationInfo for verificationId: "
+            Slog.d(TAG, "Updating IntentFilterVerificationInfo for verificationId:"
                     + verificationId);
 
             synchronized (mPackages) {
@@ -685,8 +696,7 @@
                 ivs = createDomainVerificationState(verifierId, userId, verificationId,
                         packageName);
             }
-            ArrayList<String> hosts = filter.getHostsList();
-            if (!hasValidHosts(hosts)) {
+            if (!hasValidDomains(filter)) {
                 return false;
             }
             ivs.addFilter(filter);
@@ -704,33 +714,22 @@
             }
             return ivs;
         }
+    }
 
-        private boolean hasValidHosts(ArrayList<String> hosts) {
-            if (hosts.size() == 0) {
-                Slog.d(TAG, "IntentFilter does not contain any data hosts");
-                return false;
+    private static boolean hasValidDomains(ActivityIntentInfo filter) {
+        return hasValidDomains(filter, true);
+    }
+
+    private static boolean hasValidDomains(ActivityIntentInfo filter, boolean logging) {
+        boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
+                filter.hasDataScheme(IntentFilter.SCHEME_HTTPS);
+        if (!hasHTTPorHTTPS) {
+            if (logging) {
+                Slog.d(TAG, "IntentFilter does not contain any HTTP or HTTPS data scheme");
             }
-            String hostEndBase = null;
-            for (String host : hosts) {
-                String[] hostParts = host.split("\\.");
-                // Should be at minimum a host like "example.com"
-                if (hostParts.length < 2) {
-                    Slog.d(TAG, "IntentFilter does not contain a valid data host name: " + host);
-                    return false;
-                }
-                // Verify that we have the same ending domain
-                int length = hostParts.length;
-                String hostEnd = hostParts[length - 1] + hostParts[length - 2];
-                if (hostEndBase == null) {
-                    hostEndBase = hostEnd;
-                }
-                if (!hostEnd.equalsIgnoreCase(hostEndBase)) {
-                    Slog.d(TAG, "IntentFilter does not contain the same data domains");
-                    return false;
-                }
-            }
-            return true;
+            return false;
         }
+        return true;
     }
 
     private IntentFilterVerifier mIntentFilterVerifier;
@@ -863,6 +862,9 @@
     final SparseArray<PostInstallData> mRunningInstalls = new SparseArray<PostInstallData>();
     int mNextInstallToken = 1;  // nonzero; will be wrapped back to 1 when ++ overflows
 
+    // backup/restore of preferred activity state
+    private static final String TAG_PREFERRED_BACKUP = "pa";
+
     private final String mRequiredVerifierPackage;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
@@ -1525,6 +1527,27 @@
         }
     }
 
+    private StorageEventListener mStorageListener = new StorageEventListener() {
+        @Override
+        public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+            if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+                if (vol.state == VolumeInfo.STATE_MOUNTED) {
+                    loadPrivatePackages(vol);
+                } else if (vol.state == VolumeInfo.STATE_UNMOUNTING) {
+                    unloadPrivatePackages(vol);
+                }
+            }
+
+            if (vol.isPrimary() && vol.type == VolumeInfo.TYPE_PUBLIC) {
+                if (vol.state == VolumeInfo.STATE_MOUNTED) {
+                    updateExternalMediaStatus(true, false);
+                } else if (vol.state == VolumeInfo.STATE_UNMOUNTING) {
+                    updateExternalMediaStatus(false, false);
+                }
+            }
+        }
+    };
+
     private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId) {
         if (userId >= UserHandle.USER_OWNER) {
             grantRequestedRuntimePermissionsForUser(pkg, userId);
@@ -1793,18 +1816,10 @@
                         }
 
                         try {
-                            byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
-                                                                                 dexCodeInstructionSet,
-                                                                                 false);
-                            if (dexoptRequired != DexFile.UP_TO_DATE) {
+                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
+                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                 alreadyDexOpted.add(lib);
-
-                                // The list of "shared libraries" we have at this point is
-                                if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
-                                    mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
-                                } else {
-                                    mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
-                                }
+                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
@@ -1850,13 +1865,9 @@
                             continue;
                         }
                         try {
-                            byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
-                                                                                 dexCodeInstructionSet,
-                                                                                 false);
-                            if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
-                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
-                            } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
-                                mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
+                            int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
+                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Jar not found: " + path);
@@ -2133,12 +2144,14 @@
 
             mRequiredVerifierPackage = getRequiredVerifierLPr();
 
-            mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
+            mInstallerService = new PackageInstallerService(context, this);
 
             mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
             mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                     mIntentFilterVerifierComponent);
 
+            primeDomainVerificationsLPw(false);
+
         } // synchronized (mPackages)
         } // synchronized (mInstallLock)
 
@@ -2235,6 +2248,50 @@
         return verifierComponentName;
     }
 
+    private void primeDomainVerificationsLPw(boolean logging) {
+        Slog.d(TAG, "Start priming domain verification");
+        boolean updated = false;
+        ArrayList<String> allHosts = new ArrayList<>();
+        for (PackageParser.Package pkg : mPackages.values()) {
+            final String packageName = pkg.packageName;
+            if (!hasDomainURLs(pkg)) {
+                if (logging) {
+                    Slog.d(TAG, "No priming domain verifications for " +
+                            "package with no domain URLs: " + packageName);
+                }
+                continue;
+            }
+            for (PackageParser.Activity a : pkg.activities) {
+                for (ActivityIntentInfo filter : a.intents) {
+                    if (hasValidDomains(filter, false)) {
+                        allHosts.addAll(filter.getHostsList());
+                    }
+                }
+            }
+            if (allHosts.size() > 0) {
+                allHosts.add("*");
+            }
+            IntentFilterVerificationInfo ivi =
+                    mSettings.createIntentFilterVerificationIfNeededLPw(packageName, allHosts);
+            if (ivi != null) {
+                // We will always log this
+                Slog.d(TAG, "Priming domain verifications for package: " + packageName);
+                ivi.setStatus(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS);
+                updated = true;
+            }
+            else {
+                if (logging) {
+                    Slog.d(TAG, "No priming domain verifications for package: " + packageName);
+                }
+            }
+            allHosts.clear();
+        }
+        if (updated) {
+            scheduleWriteSettingsLocked();
+        }
+        Slog.d(TAG, "End priming domain verification");
+    }
+
     @Override
     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
             throws RemoteException {
@@ -2254,9 +2311,10 @@
         removeDataDirsLI(ps.name);
         if (ps.codePath != null) {
             if (ps.codePath.isDirectory()) {
-                FileUtils.deleteContents(ps.codePath);
+                mInstaller.rmPackageDir(ps.codePath.getAbsolutePath());
+            } else {
+                ps.codePath.delete();
             }
-            ps.codePath.delete();
         }
         if (ps.resourcePath != null && !ps.resourcePath.equals(ps.codePath)) {
             if (ps.resourcePath.isDirectory()) {
@@ -3858,8 +3916,7 @@
                 resolveInfo = queryCrossProfileIntents(
                         matchingFilters, intent, resolvedType, flags, userId);
 
-                // Check for results in the current profile. Adding GET_RESOLVED_FILTER flags
-                // as we need it later
+                // Check for results in the current profile.
                 List<ResolveInfo> result = mActivities.queryIntent(
                         intent, resolvedType, flags, userId);
                 if (resolveInfo != null) {
@@ -3867,10 +3924,9 @@
                     Collections.sort(result, mResolvePrioritySorter);
                 }
                 result = filterIfNotPrimaryUser(result, userId);
-                if (result.size() > 1) {
-                    return filterCandidatesWithDomainPreferedActivitiesLPw(result);
+                if (result.size() > 1 && hasWebURI(intent)) {
+                    return filterCandidatesWithDomainPreferedActivitiesLPr(result);
                 }
-
                 return result;
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
@@ -3902,42 +3958,67 @@
         return resolveInfos;
     }
 
-    private List<ResolveInfo> filterCandidatesWithDomainPreferedActivitiesLPw(
+    private static boolean hasWebURI(Intent intent) {
+        if (intent.getData() == null) {
+            return false;
+        }
+        final String scheme = intent.getScheme();
+        if (TextUtils.isEmpty(scheme)) {
+            return false;
+        }
+        return scheme.equals(IntentFilter.SCHEME_HTTP) || scheme.equals(IntentFilter.SCHEME_HTTPS);
+    }
+
+    private List<ResolveInfo> filterCandidatesWithDomainPreferedActivitiesLPr(
             List<ResolveInfo> candidates) {
         if (DEBUG_PREFERRED) {
             Slog.v("TAG", "Filtering results with prefered activities. Candidates count: " +
                     candidates.size());
         }
+
         final int userId = UserHandle.getCallingUserId();
-        ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>(candidates);
+        ArrayList<ResolveInfo> result = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> undefinedList = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> neverList = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> matchAllList = new ArrayList<ResolveInfo>();
+
         synchronized (mPackages) {
-            final int count = result.size();
-            for (int n = count-1; n >= 0; n--) {
-                ResolveInfo info = result.get(n);
-                if (!info.filterNeedsVerification) {
-                    continue;
-                }
+            final int count = candidates.size();
+            // First, try to use the domain prefered App
+            for (int n=0; n<count; n++) {
+                ResolveInfo info = candidates.get(n);
                 String packageName = info.activityInfo.packageName;
                 PackageSetting ps = mSettings.mPackages.get(packageName);
                 if (ps != null) {
                     // Try to get the status from User settings first
-                    int status = ps.getDomainVerificationStatusForUser(userId);
-                    // if none available, get the master status
-                    if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
-                        if (ps.getIntentFilterVerificationInfo() != null) {
-                            status = ps.getIntentFilterVerificationInfo().getStatus();
-                        }
-                    }
+                    int status = getDomainVerificationStatusLPr(ps, userId);
                     if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
-                        result.clear();
                         result.add(info);
-                        // We break the for loop as we are good to go
-                        break;
                     } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
-                        result.remove(n);
+                        neverList.add(info);
+                    } else if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+                        undefinedList.add(info);
+                    }
+                    // Add to the special match all list (Browser use case)
+                    if (info.handleAllWebDataURI) {
+                        matchAllList.add(info);
                     }
                 }
             }
+            // If there is nothing selected, add all candidates and remove the ones that the User
+            // has explicitely put into the INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER state and
+            // also remove any Browser Apps ones.
+            // If there is still none after this pass, add all undefined one and Browser Apps and
+            // let the User decide with the Disambiguation dialog if there are several ones.
+            if (result.size() == 0) {
+                result.addAll(candidates);
+            }
+            result.removeAll(neverList);
+            result.removeAll(matchAllList);
+            if (result.size() == 0) {
+                result.addAll(undefinedList);
+                result.addAll(matchAllList);
+            }
         }
         if (DEBUG_PREFERRED) {
             Slog.v("TAG", "Filtered results with prefered activities. New candidates count: " +
@@ -3946,6 +4027,17 @@
         return result;
     }
 
+    private int getDomainVerificationStatusLPr(PackageSetting ps, int userId) {
+        int status = ps.getDomainVerificationStatusForUser(userId);
+        // if none available, get the master status
+        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED) {
+            if (ps.getIntentFilterVerificationInfo() != null) {
+                status = ps.getIntentFilterVerificationInfo().getStatus();
+            }
+        }
+        return status;
+    }
+
     private ResolveInfo querySkipCurrentProfileIntents(
             List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
             int flags, int sourceUserId) {
@@ -4705,9 +4797,10 @@
                         e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                     logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
                     if (file.isDirectory()) {
-                        FileUtils.deleteContents(file);
+                        mInstaller.rmPackageDir(file.getAbsolutePath());
+                    } else {
+                        file.delete();
                     }
-                    file.delete();
                 }
             }
         }
@@ -5155,7 +5248,7 @@
             // Give priority to system apps.
             for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                 PackageParser.Package pkg = it.next();
-                if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
                     if (DEBUG_DEXOPT) {
                         Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName);
                     }
@@ -5166,7 +5259,7 @@
             // Give priority to updated system apps.
             for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                 PackageParser.Package pkg = it.next();
-                if (isUpdatedSystemApp(pkg)) {
+                if (pkg.isUpdatedSystemApp()) {
                     if (DEBUG_DEXOPT) {
                         Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName);
                     }
@@ -5287,14 +5380,6 @@
         return performDexOpt(packageName, instructionSet, false);
     }
 
-    private static String getPrimaryInstructionSet(ApplicationInfo info) {
-        if (info.primaryCpuAbi == null) {
-            return getPreferredInstructionSet();
-        }
-
-        return VMRuntime.getInstructionSet(info.primaryCpuAbi);
-    }
-
     public boolean performDexOpt(String packageName, String instructionSet, boolean backgroundDexopt) {
         boolean dexopt = mLazyDexOpt || backgroundDexopt;
         boolean updateUsage = !backgroundDexopt;  // Don't update usage if this is just a backgroundDexopt
@@ -6050,7 +6135,7 @@
         final String path = scanFile.getPath();
         final String codePath = pkg.applicationInfo.getCodePath();
         final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
-        if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+        if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
             setBundledAppAbisAndRoots(pkg, pkgSetting);
 
             // If we haven't found any native libraries for the app, check if it has
@@ -6265,7 +6350,6 @@
                 throw new PackageManagerException(INSTALL_FAILED_DEXOPT, "scanPackageLI");
             }
         }
-
         if (mFactoryTest && pkg.requestedPermissions.contains(
                 android.Manifest.permission.FACTORY_TEST)) {
             pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
@@ -6281,7 +6365,7 @@
                     for (int i=0; i<pkg.libraryNames.size(); i++) {
                         String name = pkg.libraryNames.get(i);
                         boolean allowed = false;
-                        if (isUpdatedSystemApp(pkg)) {
+                        if (pkg.isUpdatedSystemApp()) {
                             // New library entries can only be added through the
                             // system image.  This is important to get rid of a lot
                             // of nasty edge cases: for example if we allowed a non-
@@ -6401,21 +6485,11 @@
             // Add the package's KeySets to the global KeySetManagerService
             KeySetManagerService ksms = mSettings.mKeySetManagerService;
             try {
-                // Old KeySetData no longer valid.
-                ksms.removeAppKeySetDataLPw(pkg.packageName);
                 ksms.addSigningKeySetToPackageLPw(pkg.packageName, pkg.mSigningKeys);
                 if (pkg.mKeySetMapping != null) {
-                    for (Map.Entry<String, ArraySet<PublicKey>> entry :
-                            pkg.mKeySetMapping.entrySet()) {
-                        if (entry.getValue() != null) {
-                            ksms.addDefinedKeySetToPackageLPw(pkg.packageName,
-                                                          entry.getValue(), entry.getKey());
-                        }
-                    }
+                    ksms.addDefinedKeySetsToPackageLPw(pkg.packageName, pkg.mKeySetMapping);
                     if (pkg.mUpgradeKeySets != null) {
-                        for (String upgradeAlias : pkg.mUpgradeKeySets) {
-                            ksms.addUpgradeKeySetToPackageLPw(pkg.packageName, upgradeAlias);
-                        }
+                        ksms.addUpgradeKeySetsToPackageLPw(pkg.packageName, pkg.mUpgradeKeySets);
                     }
                 }
             } catch (NullPointerException e) {
@@ -6887,7 +6961,7 @@
         final ApplicationInfo info = pkg.applicationInfo;
         final String codePath = pkg.codePath;
         final File codeFile = new File(codePath);
-        final boolean bundledApp = isSystemApp(info) && !isUpdatedSystemApp(info);
+        final boolean bundledApp = info.isSystemApp() && !info.isUpdatedSystemApp();
         final boolean asecApp = info.isForwardLocked() || isExternal(info);
 
         info.nativeLibraryRootDir = null;
@@ -7397,8 +7471,10 @@
 
         if (replace) {
             ps.installPermissionsFixed = false;
-            origPermissions = new PermissionsState(permissionsState);
-            permissionsState.reset();
+            if (!ps.isSharedUser()) {
+                origPermissions = new PermissionsState(permissionsState);
+                permissionsState.reset();
+            }
         }
 
         permissionsState.setGlobalGids(mGlobalGids);
@@ -7620,7 +7696,7 @@
             if (isSystemApp(pkg)) {
                 // For updated system applications, a system permission
                 // is granted only if it had been defined by the original application.
-                if (isUpdatedSystemApp(pkg)) {
+                if (pkg.isUpdatedSystemApp()) {
                     final PackageSetting sysPs = mSettings
                             .getDisabledSystemPkgLPr(pkg.packageName);
                     if (sysPs.getPermissionsState().hasInstallPermission(perm)) {
@@ -7705,7 +7781,7 @@
         }
 
         public final void addActivity(PackageParser.Activity a, String type) {
-            final boolean systemApp = isSystemApp(a.info.applicationInfo);
+            final boolean systemApp = a.info.applicationInfo.isSystemApp();
             mActivities.put(a.getComponentName(), a);
             if (DEBUG_SHOW_INFO)
                 Log.v(
@@ -7820,7 +7896,7 @@
                 res.filter = info;
             }
             if (info != null) {
-                res.filterNeedsVerification = info.needsVerification();
+                res.handleAllWebDataURI = info.handleAllWebDataURI();
             }
             res.priority = info.getPriority();
             res.preferredOrder = activity.owner.mPreferredOrder;
@@ -7835,7 +7911,7 @@
             } else {
                 res.icon = info.icon;
             }
-            res.system = isSystemApp(res.activityInfo.applicationInfo);
+            res.system = res.activityInfo.applicationInfo.isSystemApp();
             return res;
         }
 
@@ -8049,7 +8125,7 @@
             res.labelRes = info.labelRes;
             res.nonLocalizedLabel = info.nonLocalizedLabel;
             res.icon = info.icon;
-            res.system = isSystemApp(res.serviceInfo.applicationInfo);
+            res.system = res.serviceInfo.applicationInfo.isSystemApp();
             return res;
         }
 
@@ -8272,7 +8348,7 @@
             res.labelRes = info.labelRes;
             res.nonLocalizedLabel = info.nonLocalizedLabel;
             res.icon = info.icon;
-            res.system = isSystemApp(res.providerInfo.applicationInfo);
+            res.system = res.providerInfo.applicationInfo.isSystemApp();
             return res;
         }
 
@@ -8464,8 +8540,8 @@
     public void installPackage(String originPath, IPackageInstallObserver2 observer,
             int installFlags, String installerPackageName, VerificationParams verificationParams,
             String packageAbiOverride) {
-        installPackageAsUser(originPath, observer, installFlags, installerPackageName, verificationParams,
-                packageAbiOverride, UserHandle.getCallingUserId());
+        installPackageAsUser(originPath, observer, installFlags, installerPackageName,
+                verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
     }
 
     @Override
@@ -8505,6 +8581,15 @@
             user = new UserHandle(userId);
         }
 
+        // Only system components can circumvent runtime permissions when installing.
+        if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
+                && mContext.checkCallingOrSelfPermission(Manifest.permission
+                .INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
+            throw new SecurityException("You need the "
+                    + "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+                    + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
+        }
+
         verificationParams.setInstallerUid(callingUid);
 
         final File originFile = new File(originPath);
@@ -8512,7 +8597,7 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         msg.obj = new InstallParams(origin, observer, installFlags,
-                installerPackageName, verificationParams, user, packageAbiOverride);
+                installerPackageName, null, verificationParams, user, packageAbiOverride);
         mHandler.sendMessage(msg);
     }
 
@@ -8531,7 +8616,7 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         msg.obj = new InstallParams(origin, observer, params.installFlags,
-                installerPackageName, verifParams, user, params.abiOverride);
+                installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride);
         mHandler.sendMessage(msg);
     }
 
@@ -8662,7 +8747,6 @@
         long callingId = Binder.clearCallingIdentity();
         try {
             boolean sendAdded = false;
-            Bundle extras = new Bundle(1);
 
             // writer
             synchronized (mPackages) {
@@ -8921,7 +9005,7 @@
     }
 
     @Override
-    public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains)
+    public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)
             throws RemoteException {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
@@ -8929,7 +9013,7 @@
 
         final Message msg = mHandler.obtainMessage(INTENT_FILTER_VERIFIED);
         final IntentFilterVerificationResponse response = new IntentFilterVerificationResponse(
-                Binder.getCallingUid(), verificationCode, outFailedDomains);
+                Binder.getCallingUid(), verificationCode, failedDomains);
         msg.arg1 = id;
         msg.obj = response;
         mHandler.sendMessage(msg);
@@ -8959,6 +9043,42 @@
         }
     }
 
+    @Override
+    public List<IntentFilter> getAllIntentFilters(String packageName) {
+        if (TextUtils.isEmpty(packageName)) {
+            return Collections.<IntentFilter>emptyList();
+        }
+        synchronized (mPackages) {
+            PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg == null || pkg.activities == null) {
+                return Collections.<IntentFilter>emptyList();
+            }
+            final int count = pkg.activities.size();
+            ArrayList<IntentFilter> result = new ArrayList<>();
+            for (int n=0; n<count; n++) {
+                PackageParser.Activity activity = pkg.activities.get(n);
+                if (activity.intents != null || activity.intents.size() > 0) {
+                    result.addAll(activity.intents);
+                }
+            }
+            return result;
+        }
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        synchronized (mPackages) {
+            return mSettings.setDefaultBrowserPackageNameLPr(packageName, userId);
+        }
+    }
+
+    @Override
+    public String getDefaultBrowserPackageName(int userId) {
+        synchronized (mPackages) {
+            return mSettings.getDefaultBrowserPackageNameLPw(userId);
+        }
+    }
+
     /**
      * Get the "allow unknown sources" setting.
      *
@@ -9333,19 +9453,21 @@
         final IPackageInstallObserver2 observer;
         int installFlags;
         final String installerPackageName;
+        final String volumeUuid;
         final VerificationParams verificationParams;
         private InstallArgs mArgs;
         private int mRet;
         final String packageAbiOverride;
 
         InstallParams(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
-                String installerPackageName, VerificationParams verificationParams, UserHandle user,
-                String packageAbiOverride) {
+                String installerPackageName, String volumeUuid,
+                VerificationParams verificationParams, UserHandle user, String packageAbiOverride) {
             super(user);
             this.origin = origin;
             this.observer = observer;
             this.installFlags = installFlags;
             this.installerPackageName = installerPackageName;
+            this.volumeUuid = volumeUuid;
             this.verificationParams = verificationParams;
             this.packageAbiOverride = packageAbiOverride;
         }
@@ -9699,7 +9821,7 @@
      * @param installFlags package installation flags
      * @return true if should be installed on external storage
      */
-    private static boolean installOnSd(int installFlags) {
+    private static boolean installOnExternalAsec(int installFlags) {
         if ((installFlags & PackageManager.INSTALL_INTERNAL) != 0) {
             return false;
         }
@@ -9720,7 +9842,7 @@
     }
 
     private InstallArgs createInstallArgs(InstallParams params) {
-        if (installOnSd(params.installFlags) || params.isForwardLocked()) {
+        if (installOnExternalAsec(params.installFlags) || params.isForwardLocked()) {
             return new AsecInstallArgs(params);
         } else {
             return new FileInstallArgs(params);
@@ -9734,7 +9856,7 @@
     private InstallArgs createInstallArgsForExisting(int installFlags, String codePath,
             String resourcePath, String nativeLibraryRoot, String[] instructionSets) {
         final boolean isInAsec;
-        if (installOnSd(installFlags)) {
+        if (installOnExternalAsec(installFlags)) {
             /* Apps on SD card are always in ASEC containers. */
             isInAsec = true;
         } else if (installForwardLocked(installFlags)
@@ -9750,7 +9872,7 @@
 
         if (isInAsec) {
             return new AsecInstallArgs(codePath, instructionSets,
-                    installOnSd(installFlags), installForwardLocked(installFlags));
+                    installOnExternalAsec(installFlags), installForwardLocked(installFlags));
         } else {
             return new FileInstallArgs(codePath, resourcePath, nativeLibraryRoot,
                     instructionSets);
@@ -9765,6 +9887,7 @@
         // Always refers to PackageManager flags only
         final int installFlags;
         final String installerPackageName;
+        final String volumeUuid;
         final ManifestDigest manifestDigest;
         final UserHandle user;
         final String abiOverride;
@@ -9775,12 +9898,13 @@
         /* nullable */ String[] instructionSets;
 
         InstallArgs(OriginInfo origin, IPackageInstallObserver2 observer, int installFlags,
-                String installerPackageName, ManifestDigest manifestDigest, UserHandle user,
-                String[] instructionSets, String abiOverride) {
+                String installerPackageName, String volumeUuid, ManifestDigest manifestDigest,
+                UserHandle user, String[] instructionSets, String abiOverride) {
             this.origin = origin;
             this.installFlags = installFlags;
             this.observer = observer;
             this.installerPackageName = installerPackageName;
+            this.volumeUuid = volumeUuid;
             this.manifestDigest = manifestDigest;
             this.user = user;
             this.instructionSets = instructionSets;
@@ -9832,7 +9956,7 @@
             return (installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
         }
 
-        protected boolean isExternal() {
+        protected boolean isExternalAsec() {
             return (installFlags & PackageManager.INSTALL_EXTERNAL) != 0;
         }
 
@@ -9879,8 +10003,8 @@
         /** New install */
         FileInstallArgs(InstallParams params) {
             super(params.origin, params.observer, params.installFlags,
-                    params.installerPackageName, params.getManifestDigest(), params.getUser(),
-                    null /* instruction sets */, params.packageAbiOverride);
+                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.getUser(), null /* instruction sets */, params.packageAbiOverride);
             if (isFwdLocked()) {
                 throw new IllegalArgumentException("Forward locking only supported in ASEC");
             }
@@ -9889,7 +10013,7 @@
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String legacyNativeLibraryPath,
                 String[] instructionSets) {
-            super(OriginInfo.fromNothing(), null, 0, null, null, null, instructionSets, null);
+            super(OriginInfo.fromNothing(), null, 0, null, null, null, null, instructionSets, null);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
             this.legacyNativeLibraryPath = (legacyNativeLibraryPath != null) ?
@@ -9913,7 +10037,7 @@
             }
 
             try {
-                final File tempDir = mInstallerService.allocateInternalStageDirLegacy();
+                final File tempDir = mInstallerService.allocateStageDirLegacy(volumeUuid);
                 codeFile = tempDir;
                 resourceFile = tempDir;
             } catch (IOException e) {
@@ -9974,8 +10098,9 @@
                 cleanUp();
                 return false;
             } else {
+                final File targetDir = codeFile.getParentFile();
                 final File beforeCodeFile = codeFile;
-                final File afterCodeFile = getNextCodePath(pkg.packageName);
+                final File afterCodeFile = getNextCodePath(targetDir, pkg.packageName);
 
                 Slog.d(TAG, "Renaming " + beforeCodeFile + " to " + afterCodeFile);
                 try {
@@ -10041,9 +10166,10 @@
             }
 
             if (codeFile.isDirectory()) {
-                FileUtils.deleteContents(codeFile);
+                mInstaller.rmPackageDir(codeFile.getAbsolutePath());
+            } else {
+                codeFile.delete();
             }
-            codeFile.delete();
 
             if (resourceFile != null && !FileUtils.contains(codeFile, resourceFile)) {
                 resourceFile.delete();
@@ -10124,16 +10250,15 @@
         /** New install */
         AsecInstallArgs(InstallParams params) {
             super(params.origin, params.observer, params.installFlags,
-                    params.installerPackageName, params.getManifestDigest(),
-                    params.getUser(), null /* instruction sets */,
-                    params.packageAbiOverride);
+                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.getUser(), null /* instruction sets */, params.packageAbiOverride);
         }
 
         /** Existing install */
         AsecInstallArgs(String fullCodePath, String[] instructionSets,
                         boolean isExternal, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, (isExternal ? INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
                     instructionSets, null);
             // Hackily pretend we're still looking at a full code path
             if (!fullCodePath.endsWith(RES_FILE_NAME)) {
@@ -10150,7 +10275,7 @@
 
         AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
                     instructionSets, null);
             this.cid = cid;
             setMountPath(PackageHelper.getSdDir(cid));
@@ -10165,7 +10290,7 @@
                     abiOverride);
 
             final File target;
-            if (isExternal()) {
+            if (isExternalAsec()) {
                 target = new UserEnvironment(UserHandle.USER_OWNER).getExternalStorageDirectory();
             } else {
                 target = Environment.getDataDirectory();
@@ -10194,7 +10319,7 @@
             }
 
             final String newMountPath = imcs.copyPackageToContainer(
-                    origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternal(),
+                    origin.file.getAbsolutePath(), cid, getEncryptKey(), isExternalAsec(),
                     isFwdLocked(), deriveAbiOverride(abiOverride, null /* settings */));
 
             if (newMountPath != null) {
@@ -10475,32 +10600,16 @@
         return prefix + idxStr;
     }
 
-    private File getNextCodePath(String packageName) {
+    private File getNextCodePath(File targetDir, String packageName) {
         int suffix = 1;
         File result;
         do {
-            result = new File(mAppInstallDir, packageName + "-" + suffix);
+            result = new File(targetDir, packageName + "-" + suffix);
             suffix++;
         } while (result.exists());
         return result;
     }
 
-    // Utility method used to ignore ADD/REMOVE events
-    // by directory observer.
-    private static boolean ignoreCodePath(String fullPathStr) {
-        String apkName = deriveCodePathName(fullPathStr);
-        int idx = apkName.lastIndexOf(INSTALL_PACKAGE_SUFFIX);
-        if (idx != -1 && ((idx+1) < apkName.length())) {
-            // Make sure the package ends with a numeral
-            String version = apkName.substring(idx+1);
-            try {
-                Integer.parseInt(version);
-                return true;
-            } catch (NumberFormatException e) {}
-        }
-        return false;
-    }
-    
     // Utility method that returns the relative package path with respect
     // to the installation directory. Like say for /data/data/com.test-1.apk
     // string com.test-1 is returned.
@@ -10559,9 +10668,9 @@
     /*
      * Install a non-existing package.
      */
-    private void installNewPackageLI(PackageParser.Package pkg,
-            int parseFlags, int scanFlags, UserHandle user,
-            String installerPackageName, PackageInstalledInfo res) {
+    private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
+            UserHandle user, String installerPackageName, String volumeUuid,
+            PackageInstalledInfo res) {
         // Remember this for later, in case we need to rollback this install
         String pkgName = pkg.packageName;
 
@@ -10590,7 +10699,7 @@
             PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanFlags,
                     System.currentTimeMillis(), user);
 
-            updateSettingsLI(newPackage, installerPackageName, null, null, res, user);
+            updateSettingsLI(newPackage, installerPackageName, volumeUuid, null, null, res, user);
             // delete the partially installed application. the data directory will have to be
             // restored if it was already existing
             if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
@@ -10622,9 +10731,9 @@
         return false;
     }
 
-    private void replacePackageLI(PackageParser.Package pkg,
-            int parseFlags, int scanFlags, UserHandle user,
-            String installerPackageName, PackageInstalledInfo res) {
+    private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
+            UserHandle user, String installerPackageName, String volumeUuid,
+            PackageInstalledInfo res) {
         PackageParser.Package oldPackage;
         String pkgName = pkg.packageName;
         int[] allUsers;
@@ -10663,17 +10772,17 @@
         boolean sysPkg = (isSystemApp(oldPackage));
         if (sysPkg) {
             replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
-                    user, allUsers, perUserInstalled, installerPackageName, res);
+                    user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
         } else {
             replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
-                    user, allUsers, perUserInstalled, installerPackageName, res);
+                    user, allUsers, perUserInstalled, installerPackageName, volumeUuid, res);
         }
     }
 
     private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
-            int[] allUsers, boolean[] perUserInstalled,
-            String installerPackageName, PackageInstalledInfo res) {
+            int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
+            String volumeUuid, PackageInstalledInfo res) {
         String pkgName = deletedPackage.packageName;
         boolean deletedPkg = true;
         boolean updatedSettings = false;
@@ -10712,8 +10821,8 @@
             try {
                 final PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags,
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
-                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
-                        user);
+                updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
+                        perUserInstalled, res, user);
                 updatedSettings = true;
             } catch (PackageManagerException e) {
                 res.setError("Package couldn't be installed in " + pkg.codePath, e);
@@ -10738,10 +10847,10 @@
                 if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage);
                 File restoreFile = new File(deletedPackage.codePath);
                 // Parse old package
-                boolean oldOnSd = isExternal(deletedPackage);
+                boolean oldExternal = isExternal(deletedPackage);
                 int oldParseFlags  = mDefParseFlags | PackageParser.PARSE_CHATTY |
                         (deletedPackage.isForwardLocked() ? PackageParser.PARSE_FORWARD_LOCK : 0) |
-                        (oldOnSd ? PackageParser.PARSE_ON_SDCARD : 0);
+                        (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
                 int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
                 try {
                     scanPackageLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null);
@@ -10765,8 +10874,8 @@
 
     private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
-            int[] allUsers, boolean[] perUserInstalled,
-            String installerPackageName, PackageInstalledInfo res) {
+            int[] allUsers, boolean[] perUserInstalled, String installerPackageName,
+            String volumeUuid, PackageInstalledInfo res) {
         if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
                 + ", old=" + deletedPackage);
         boolean disabledSystem = false;
@@ -10843,8 +10952,8 @@
             }
 
             if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
-                updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res,
-                        user);
+                updateSettingsLI(newPackage, installerPackageName, volumeUuid, allUsers,
+                        perUserInstalled, res, user);
                 updatedSettings = true;
             }
 
@@ -10879,8 +10988,8 @@
     }
 
     private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName,
-            int[] allUsers, boolean[] perUserInstalled,
-            PackageInstalledInfo res, UserHandle user) {
+            String volumeUuid, int[] allUsers, boolean[] perUserInstalled, PackageInstalledInfo res,
+            UserHandle user) {
         String pkgName = newPackage.packageName;
         synchronized (mPackages) {
             //write settings. the installStatus will be incomplete at this stage.
@@ -10938,6 +11047,7 @@
             res.pkg = newPackage;
             mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE);
             mSettings.setInstallerPackageName(pkgName, installerPackageName);
+            mSettings.setVolumeUuid(pkgName, volumeUuid);
             res.returnCode = PackageManager.INSTALL_SUCCEEDED;
             //to update install status
             mSettings.writeLPr();
@@ -10946,10 +11056,12 @@
 
     private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
         final int installFlags = args.installFlags;
-        String installerPackageName = args.installerPackageName;
-        File tmpPackageFile = new File(args.getCodePath());
-        boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
-        boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
+        final String installerPackageName = args.installerPackageName;
+        final String volumeUuid = args.volumeUuid;
+        final File tmpPackageFile = new File(args.getCodePath());
+        final boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
+        final boolean onExternal = (((installFlags & PackageManager.INSTALL_EXTERNAL) != 0)
+                || (args.volumeUuid != null));
         boolean replace = false;
         final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
         // Result object to be returned
@@ -10959,7 +11071,7 @@
         // Retrieve PackageSettings and parse package
         final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                 | (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0)
-                | (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
+                | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
         PackageParser pp = new PackageParser();
         pp.setSeparateProcesses(mSeparateProcesses);
         pp.setDisplayMetrics(mMetrics);
@@ -11111,13 +11223,22 @@
 
         }
 
-        if (systemApp && onSd) {
+        if (systemApp && onExternal) {
             // Disable updates to system apps on sdcard
             res.setError(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                     "Cannot install updates to system apps on sdcard");
             return;
         }
 
+        // Run dexopt before old package gets removed, to minimize time when app is not available
+        int result = mPackageDexOptimizer
+                .performDexOpt(pkg, null /* instruction sets */, true /* forceDex */,
+                        false /* defer */, false /* inclDependencies */);
+        if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
+            res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
+            return;
+        }
+
         if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
             res.setError(INSTALL_FAILED_INSUFFICIENT_STORAGE, "Failed rename");
             return;
@@ -11125,12 +11246,13 @@
 
         startIntentFilterVerifications(args.user.getIdentifier(), pkg);
 
+        // Call with SCAN_NO_DEX, since dexopt has already been made
         if (replace) {
-            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
-                    installerPackageName, res);
+            replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING | SCAN_NO_DEX, args.user,
+                    installerPackageName, volumeUuid, res);
         } else {
-            installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
-                    args.user, installerPackageName, res);
+            installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES
+                    | SCAN_NO_DEX, args.user, installerPackageName, volumeUuid, res);
         }
         synchronized (mPackages) {
             final PackageSetting ps = mSettings.mPackages.get(pkgName);
@@ -11161,30 +11283,45 @@
     }
 
     private void verifyIntentFiltersIfNeeded(int userId, int verifierUid,
-                                             PackageParser.Package pkg) {
+            PackageParser.Package pkg) {
         int size = pkg.activities.size();
         if (size == 0) {
             Slog.d(TAG, "No activity, so no need to verify any IntentFilter!");
             return;
         }
 
+        final boolean hasDomainURLs = hasDomainURLs(pkg);
+        if (!hasDomainURLs) {
+            Slog.d(TAG, "No domain URLs, so no need to verify any IntentFilter!");
+            return;
+        }
+
         Slog.d(TAG, "Checking for userId:" + userId + " if any IntentFilter from the " + size
                 + " Activities needs verification ...");
 
         final int verificationId = mIntentFilterVerificationToken++;
         int count = 0;
+        final String packageName = pkg.packageName;
+        ArrayList<String> allHosts = new ArrayList<>();
+
         synchronized (mPackages) {
             for (PackageParser.Activity a : pkg.activities) {
                 for (ActivityIntentInfo filter : a.intents) {
-                    boolean needFilterVerification = filter.needsVerification() &&
-                            !filter.isVerified();
-                    if (needFilterVerification && needNetworkVerificationLPr(filter)) {
+                    boolean needsFilterVerification = filter.needsVerification();
+                    if (needsFilterVerification && needsNetworkVerificationLPr(filter)) {
                         Slog.d(TAG, "Verification needed for IntentFilter:" + filter.toString());
                         mIntentFilterVerifier.addOneIntentFilterVerification(
-                                verifierUid, userId, verificationId, filter, pkg.packageName);
+                                verifierUid, userId, verificationId, filter, packageName);
                         count++;
+                    } else if (!needsFilterVerification) {
+                        Slog.d(TAG, "No verification needed for IntentFilter:"
+                                + filter.toString());
+                        if (hasValidDomains(filter)) {
+                            allHosts.addAll(filter.getHostsList());
+                        }
                     } else {
-                        Slog.d(TAG, "No verification needed for IntentFilter:" + filter.toString());
+                        Slog.d(TAG, "Verification already done for IntentFilter:"
+                                + filter.toString());
                     }
                 }
             }
@@ -11196,10 +11333,14 @@
                     + (count > 1 ? "s" : "") +  " for userId:" + userId + "!");
         } else {
             Slog.d(TAG, "No need to start any IntentFilter verification!");
+            if (allHosts.size() > 0 && mSettings.createIntentFilterVerificationIfNeededLPw(
+                    packageName, allHosts) != null) {
+                scheduleWriteSettingsLocked();
+            }
         }
     }
 
-    private boolean needNetworkVerificationLPr(ActivityIntentInfo filter) {
+    private boolean needsNetworkVerificationLPr(ActivityIntentInfo filter) {
         final ComponentName cn  = filter.activity.getComponentName();
         final String packageName = cn.getPackageName();
 
@@ -11248,8 +11389,8 @@
         return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
     }
 
-    private static boolean isSystemApp(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+    private static boolean hasDomainURLs(PackageParser.Package pkg) {
+        return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
     }
 
     private static boolean isSystemApp(PackageSetting ps) {
@@ -11260,17 +11401,11 @@
         return (ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
     }
 
-    private static boolean isUpdatedSystemApp(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
-    private static boolean isUpdatedSystemApp(ApplicationInfo info) {
-        return (info.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
-    }
-
     private int packageFlagsToInstallFlags(PackageSetting ps) {
         int installFlags = 0;
-        if (isExternal(ps)) {
+        if (isExternal(ps) && TextUtils.isEmpty(ps.volumeUuid)) {
+            // This existing package was an external ASEC install when we have
+            // the external flag without a UUID
             installFlags |= PackageManager.INSTALL_EXTERNAL;
         }
         if (ps.isForwardLocked()) {
@@ -12538,6 +12673,83 @@
         }
     }
 
+    /**
+     * Non-Binder method, support for the backup/restore mechanism: write the
+     * full set of preferred activities in its canonical XML format.  Returns true
+     * on success; false otherwise.
+     */
+    @Override
+    public byte[] getPreferredActivityBackup(int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call getPreferredActivityBackup()");
+        }
+
+        ByteArrayOutputStream dataStream = new ByteArrayOutputStream();
+        try {
+            final XmlSerializer serializer = new FastXmlSerializer();
+            serializer.setOutput(dataStream, "utf-8");
+            serializer.startDocument(null, true);
+            serializer.startTag(null, TAG_PREFERRED_BACKUP);
+
+            synchronized (mPackages) {
+                mSettings.writePreferredActivitiesLPr(serializer, userId, true);
+            }
+
+            serializer.endTag(null, TAG_PREFERRED_BACKUP);
+            serializer.endDocument();
+            serializer.flush();
+        } catch (Exception e) {
+            if (DEBUG_BACKUP) {
+                Slog.e(TAG, "Unable to write preferred activities for backup", e);
+            }
+            return null;
+        }
+
+        return dataStream.toByteArray();
+    }
+
+    @Override
+    public void restorePreferredActivities(byte[] backup, int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call restorePreferredActivities()");
+        }
+
+        try {
+            final XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(new ByteArrayInputStream(backup), null);
+
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+            }
+            if (type != XmlPullParser.START_TAG) {
+                // oops didn't find a start tag?!
+                if (DEBUG_BACKUP) {
+                    Slog.e(TAG, "Didn't find start tag during restore");
+                }
+                return;
+            }
+
+            // this is supposed to be TAG_PREFERRED_BACKUP
+            if (!TAG_PREFERRED_BACKUP.equals(parser.getName())) {
+                if (DEBUG_BACKUP) {
+                    Slog.e(TAG, "Found unexpected tag " + parser.getName());
+                }
+                return;
+            }
+
+            // skip interfering stuff, then we're aligned with the backing implementation
+            while ((type = parser.next()) == XmlPullParser.TEXT) { }
+            synchronized (mPackages) {
+                mSettings.readPreferredActivitiesLPw(parser, userId);
+            }
+        } catch (Exception e) {
+            if (DEBUG_BACKUP) {
+                Slog.e(TAG, "Exception restoring preferred activities: " + e.getMessage());
+            }
+        }
+    }
+
     @Override
     public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
             int sourceUserId, int targetUserId, int flags) {
@@ -12899,6 +13111,12 @@
             }
             mPostSystemReadyMessages = null;
         }
+
+        // Watch for external volumes that come and go over time
+        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        storage.registerListener(mStorageListener);
+
+        mInstallerService.systemReady();
     }
 
     @Override
@@ -13637,13 +13855,32 @@
     }
 
     private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+            ArrayList<ApplicationInfo> infos, IIntentReceiver finishedReceiver) {
+        final int size = infos.size();
+        final String[] packageNames = new String[size];
+        final int[] packageUids = new int[size];
+        for (int i = 0; i < size; i++) {
+            final ApplicationInfo info = infos.get(i);
+            packageNames[i] = info.packageName;
+            packageUids[i] = info.uid;
+        }
+        sendResourcesChangedBroadcast(mediaStatus, replacing, packageNames, packageUids,
+                finishedReceiver);
+    }
+
+    private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
             ArrayList<String> pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
-        int size = pkgList.size();
+        sendResourcesChangedBroadcast(mediaStatus, replacing,
+                pkgList.toArray(new String[pkgList.size()]), uidArr, finishedReceiver);
+    }
+
+    private void sendResourcesChangedBroadcast(boolean mediaStatus, boolean replacing,
+            String[] pkgList, int uidArr[], IIntentReceiver finishedReceiver) {
+        int size = pkgList.length;
         if (size > 0) {
             // Send broadcasts here
             Bundle extras = new Bundle();
-            extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList
-                    .toArray(new String[size]));
+            extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgList);
             if (uidArr != null) {
                 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
             }
@@ -13686,8 +13923,8 @@
                 }
                 // Parse package
                 int parseFlags = mDefParseFlags;
-                if (args.isExternal()) {
-                    parseFlags |= PackageParser.PARSE_ON_SDCARD;
+                if (args.isExternalAsec()) {
+                    parseFlags |= PackageParser.PARSE_EXTERNAL_STORAGE;
                 }
                 if (args.isFwdLocked()) {
                     parseFlags |= PackageParser.PARSE_FORWARD_LOCK;
@@ -13834,73 +14071,130 @@
         }
     }
 
-    /** Binder call */
+    private void loadPrivatePackages(VolumeInfo vol) {
+        final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
+        final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
+        synchronized (mPackages) {
+            final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+            for (PackageSetting ps : packages) {
+                synchronized (mInstallLock) {
+                    final PackageParser.Package pkg;
+                    try {
+                        pkg = scanPackageLI(ps.codePath, parseFlags, 0, 0, null);
+                        loaded.add(pkg.applicationInfo);
+                    } catch (PackageManagerException e) {
+                        Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
+                    }
+                }
+            }
+
+            // TODO: regrant any permissions that changed based since original install
+
+            mSettings.writeLPr();
+        }
+
+        Slog.d(TAG, "Loaded packages " + loaded);
+        sendResourcesChangedBroadcast(true, false, loaded, null);
+    }
+
+    private void unloadPrivatePackages(VolumeInfo vol) {
+        final ArrayList<ApplicationInfo> unloaded = new ArrayList<>();
+        synchronized (mPackages) {
+            final List<PackageSetting> packages = mSettings.getVolumePackagesLPr(vol.fsUuid);
+            for (PackageSetting ps : packages) {
+                if (ps.pkg == null) continue;
+                synchronized (mInstallLock) {
+                    final ApplicationInfo info = ps.pkg.applicationInfo;
+                    final PackageRemovedInfo outInfo = new PackageRemovedInfo();
+                    if (deletePackageLI(ps.name, null, false, null, null,
+                            PackageManager.DELETE_KEEP_DATA, outInfo, false)) {
+                        unloaded.add(info);
+                    } else {
+                        Slog.w(TAG, "Failed to unload " + ps.codePath);
+                    }
+                }
+            }
+
+            mSettings.writeLPr();
+        }
+
+        Slog.d(TAG, "Unloaded packages " + unloaded);
+        sendResourcesChangedBroadcast(false, false, unloaded, null);
+    }
+
     @Override
     public void movePackage(final String packageName, final IPackageMoveObserver observer,
             final int flags) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
-        UserHandle user = new UserHandle(UserHandle.getCallingUserId());
-        int returnCode = PackageManager.MOVE_SUCCEEDED;
-        int currInstallFlags = 0;
-        int newInstallFlags = 0;
+
+        final int installFlags;
+        if ((flags & MOVE_INTERNAL) != 0) {
+            installFlags = INSTALL_INTERNAL;
+        } else if ((flags & MOVE_EXTERNAL_MEDIA) != 0) {
+            installFlags = INSTALL_EXTERNAL;
+        } else {
+            throw new IllegalArgumentException("Unsupported move flags " + flags);
+        }
+
+        try {
+            movePackageInternal(packageName, null, installFlags, false, observer);
+        } catch (PackageManagerException e) {
+            Slog.d(TAG, "Failed to move " + packageName, e);
+            try {
+                observer.packageMoved(packageName, e.error);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    @Override
+    public void movePackageAndData(final String packageName, final String volumeUuid,
+            final IPackageMoveObserver observer) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
+        try {
+            movePackageInternal(packageName, volumeUuid, INSTALL_INTERNAL, true, observer);
+        } catch (PackageManagerException e) {
+            Slog.d(TAG, "Failed to move " + packageName, e);
+            try {
+                observer.packageMoved(packageName, e.error);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    private void movePackageInternal(final String packageName, String volumeUuid, int installFlags,
+            boolean andData, final IPackageMoveObserver observer) throws PackageManagerException {
+        final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
 
         File codeFile = null;
         String installerPackageName = null;
         String packageAbiOverride = null;
 
+        // TOOD: move app private data before installing
+
         // reader
         synchronized (mPackages) {
             final PackageParser.Package pkg = mPackages.get(packageName);
             final PackageSetting ps = mSettings.mPackages.get(packageName);
             if (pkg == null || ps == null) {
-                returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
-            } else {
-                // Disable moving fwd locked apps and system packages
-                if (pkg.applicationInfo != null && isSystemApp(pkg)) {
-                    Slog.w(TAG, "Cannot move system application");
-                    returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
-                } else if (pkg.mOperationPending) {
-                    Slog.w(TAG, "Attempt to move package which has pending operations");
-                    returnCode = PackageManager.MOVE_FAILED_OPERATION_PENDING;
-                } else {
-                    // Find install location first
-                    if ((flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0
-                            && (flags & PackageManager.MOVE_INTERNAL) != 0) {
-                        Slog.w(TAG, "Ambigous flags specified for move location.");
-                        returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
-                    } else {
-                        newInstallFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0
-                                ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
-                        currInstallFlags = isExternal(pkg)
-                                ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
-
-                        if (newInstallFlags == currInstallFlags) {
-                            Slog.w(TAG, "No move required. Trying to move to same location");
-                            returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
-                        } else {
-                            if (pkg.isForwardLocked()) {
-                                currInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
-                                newInstallFlags |= PackageManager.INSTALL_FORWARD_LOCK;
-                            }
-                        }
-                    }
-                    if (returnCode == PackageManager.MOVE_SUCCEEDED) {
-                        pkg.mOperationPending = true;
-                    }
-                }
-
-                codeFile = new File(pkg.codePath);
-                installerPackageName = ps.installerPackageName;
-                packageAbiOverride = ps.cpuAbiOverrideString;
+                throw new PackageManagerException(MOVE_FAILED_DOESNT_EXIST, "Missing package");
             }
-        }
 
-        if (returnCode != PackageManager.MOVE_SUCCEEDED) {
-            try {
-                observer.packageMoved(packageName, returnCode);
-            } catch (RemoteException ignored) {
+            if (pkg.applicationInfo.isSystemApp()) {
+                throw new PackageManagerException(MOVE_FAILED_SYSTEM_PACKAGE,
+                        "Cannot move system application");
+            } else if (pkg.mOperationPending) {
+                throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
+                        "Attempt to move package which has pending operations");
             }
-            return;
+
+            // TODO: yell if already in desired location
+
+            pkg.mOperationPending = true;
+
+            codeFile = new File(pkg.codePath);
+            installerPackageName = ps.installerPackageName;
+            packageAbiOverride = ps.cpuAbiOverrideString;
         }
 
         final IPackageInstallObserver2 installObserver = new IPackageInstallObserver2.Stub() {
@@ -13942,12 +14236,12 @@
 
         // Treat a move like reinstalling an existing app, which ensures that we
         // process everythign uniformly, like unpacking native libraries.
-        newInstallFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+        installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
-        msg.obj = new InstallParams(origin, installObserver, newInstallFlags,
-                installerPackageName, null, user, packageAbiOverride);
+        msg.obj = new InstallParams(origin, installObserver, installFlags,
+                installerPackageName, volumeUuid, null, user, packageAbiOverride);
         mHandler.sendMessage(msg);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index a3f4c0b..e7c0ef7 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -74,4 +74,8 @@
     public boolean isSystem() {
         return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
     }
+
+    public boolean isSharedUser() {
+        return sharedUser != null;
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 20120de..5429517 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -23,6 +23,8 @@
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageUserState;
+import android.os.storage.VolumeInfo;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
@@ -108,8 +110,10 @@
 
     PackageSettingBase origPackage;
 
-    /* package name of the app that installed this package */
+    /** Package name of the app that installed this package */
     String installerPackageName;
+    /** UUID of {@link VolumeInfo} hosting this app */
+    String volumeUuid;
 
     IntentFilterVerificationInfo verificationInfo;
 
@@ -161,6 +165,7 @@
         origPackage = base.origPackage;
 
         installerPackageName = base.installerPackageName;
+        volumeUuid = base.volumeUuid;
 
         keySetData = new PackageKeySetData(base.keySetData);
     }
@@ -183,10 +188,18 @@
         installerPackageName = packageName;
     }
 
-    String getInstallerPackageName() {
+    public String getInstallerPackageName() {
         return installerPackageName;
     }
 
+    public void setVolumeUuid(String volumeUuid) {
+        this.volumeUuid = volumeUuid;
+    }
+
+    public String getVolumeUuid() {
+        return volumeUuid;
+    }
+
     public void setInstallStatus(int newStatus) {
         installStatus = newStatus;
     }
@@ -204,7 +217,7 @@
      */
     public void copyFrom(PackageSettingBase base) {
         setPermissionsUpdatedForUserIds(base.getPermissionsUpdatedForUserIds());
-        getPermissionsState().copyFrom(base.getPermissionsState());
+        mPermissionsState.copyFrom(base.mPermissionsState);
         primaryCpuAbiString = base.primaryCpuAbiString;
         secondaryCpuAbiString = base.secondaryCpuAbiString;
         cpuAbiOverrideString = base.cpuAbiOverrideString;
@@ -423,23 +436,23 @@
         userState.delete(userId);
     }
 
-    public IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
+    IntentFilterVerificationInfo getIntentFilterVerificationInfo() {
         return verificationInfo;
     }
 
-    public void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
+    void setIntentFilterVerificationInfo(IntentFilterVerificationInfo info) {
         verificationInfo = info;
     }
 
-    public int getDomainVerificationStatusForUser(int userId) {
+    int getDomainVerificationStatusForUser(int userId) {
         return readUserState(userId).domainVerificationStatus;
     }
 
-    public void setDomainVerificationStatusForUser(int status, int userId) {
+    void setDomainVerificationStatusForUser(int status, int userId) {
         modifyUserState(userId).domainVerificationStatus = status;
     }
 
-    public void clearDomainVerificationStatusForUser(int userId) {
+    void clearDomainVerificationStatusForUser(int userId) {
         modifyUserState(userId).domainVerificationStatus =
                 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
     }
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index 705abf8..fbb5090 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -221,13 +221,11 @@
         int result = PERMISSION_OPERATION_SUCCESS;
 
         PermissionData permissionData = mPermissions.get(permission.name);
-        if (permissionData.hasGids()) {
-            for (int userId : permissionData.getUserIds()) {
-                if (revokePermission(permission, userId)
-                        == PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
-                    result = PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
-                    break;
-                }
+        for (int userId : permissionData.getUserIds()) {
+            if (revokePermission(permission, userId)
+                    == PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED) {
+                result = PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
+                break;
             }
         }
 
@@ -380,7 +378,7 @@
             return PERMISSION_OPERATION_FAILURE;
         }
 
-        final boolean hasGids = permission.hasGids();
+        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
 
         if (mPermissions == null) {
@@ -412,7 +410,7 @@
             return PERMISSION_OPERATION_FAILURE;
         }
 
-        final boolean hasGids = permission.hasGids();
+        final boolean hasGids = !ArrayUtils.isEmpty(permission.computeGids(userId));
         final int[] oldGids = hasGids ? computeGids(userId) : NO_GIDS;
 
         PermissionData permissionData = mPermissions.get(permission.name);
@@ -472,10 +470,6 @@
             }
         }
 
-        public boolean hasGids() {
-            return mPerm.hasGids();
-        }
-
         public int[] computeGids(int userId) {
             return mPerm.computeGids(userId);
         }
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 1ff6fb8..c75a1d3 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -34,6 +34,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -52,14 +53,15 @@
  */
 public final class SELinuxMMAC {
 
-    private static final String TAG = "SELinuxMMAC";
+    static final String TAG = "SELinuxMMAC";
 
     private static final boolean DEBUG_POLICY = false;
     private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
+    private static final boolean DEBUG_POLICY_ORDER = DEBUG_POLICY || false;
 
     // All policy stanzas read from mac_permissions.xml. This is also the lock
     // to synchronize access during policy load and access attempts.
-    private static final List<Policy> sPolicies = new ArrayList<Policy>();
+    private static List<Policy> sPolicies = new ArrayList<>();
 
     // Data policy override version file.
     private static final String DATA_VERSION_FILE =
@@ -112,17 +114,9 @@
      *         were loaded successfully; no partial loading is possible.
      */
     public static boolean readInstallPolicy() {
-        // Temp structure to hold the rules while we parse the xml file. We add
-        // all the rules once we know there's no problems.
+        // Temp structure to hold the rules while we parse the xml file
         List<Policy> policies = new ArrayList<>();
 
-        // A separate structure to hold the default stanza. We need to add this to
-        // the end of the policies list structure.
-        Policy defaultPolicy = null;
-
-        // Track sets of known policy certs so we can enforce rules across stanzas.
-        Set<Set<Signature>> knownCerts = new HashSet<>();
-
         FileReader policyFile = null;
         XmlPullParser parser = Xml.newPullParser();
         try {
@@ -138,31 +132,15 @@
                     continue;
                 }
 
-                String tagName = parser.getName();
-                if ("signer".equals(tagName)) {
-                    Policy signerPolicy = readSignerOrThrow(parser);
-                    // Return of a Policy instance ensures certain invariants have
-                    // passed, however, we still want to do some cross policy checking.
-                    // Thus, check that we haven't seen the certs in another stanza.
-                    Set<Signature> certs = signerPolicy.getSignatures();
-                    if (knownCerts.contains(certs)) {
-                        String msg = "Separate stanzas have identical certs";
-                        throw new IllegalStateException(msg);
-                    }
-                    knownCerts.add(certs);
-                    policies.add(signerPolicy);
-                } else if ("default".equals(tagName)) {
-                    Policy defPolicy = readDefaultOrThrow(parser);
-                    // Return of a Policy instance ensures certain invariants have
-                    // passed, however, we still want to do some cross policy checking.
-                    // Thus, check that we haven't already seen a default stanza.
-                    if (defaultPolicy != null) {
-                        String msg = "Multiple default stanzas identified";
-                        throw new IllegalStateException(msg);
-                    }
-                    defaultPolicy = defPolicy;
-                } else {
-                    skip(parser);
+                switch (parser.getName()) {
+                    case "signer":
+                        policies.add(readSignerOrThrow(parser));
+                        break;
+                    case "default":
+                        policies.add(readDefaultOrThrow(parser));
+                        break;
+                    default:
+                        skip(parser);
                 }
             }
         } catch (IllegalStateException | IllegalArgumentException |
@@ -182,15 +160,22 @@
             IoUtils.closeQuietly(policyFile);
         }
 
-        // Add the default policy to the end if there is one. This will ensure that
-        // the default stanza is consulted last when performing policy lookups.
-        if (defaultPolicy != null) {
-            policies.add(defaultPolicy);
+        // Now sort the policy stanzas
+        PolicyComparator policySort = new PolicyComparator();
+        Collections.sort(policies, policySort);
+        if (policySort.foundDuplicate()) {
+            Slog.w(TAG, "ERROR! Duplicate entries found parsing " + MAC_PERMISSIONS);
+            return false;
         }
 
         synchronized (sPolicies) {
-            sPolicies.clear();
-            sPolicies.addAll(policies);
+            sPolicies = policies;
+
+            if (DEBUG_POLICY_ORDER) {
+                for (Policy policy : sPolicies) {
+                    Slog.d(TAG, "Policy: " + policy.toString());
+                }
+            }
         }
 
         return true;
@@ -494,9 +479,23 @@
  * of invariants before being built and returned. Each instance can be guaranteed to
  * hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml
  * file.
- * </p>
+ * <p>
  * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
- * signer based Policy instance.
+ * signer based Policy instance with only inner package name refinements.
+ * </p>
+ * <pre>
+ * {@code
+ * Policy policy = new Policy.PolicyBuilder()
+ *         .addSignature("308204a8...")
+ *         .addSignature("483538c8...")
+ *         .addInnerPackageMapOrThrow("com.foo.", "bar")
+ *         .addInnerPackageMapOrThrow("com.foo.other", "bar")
+ *         .build();
+ * }
+ * </pre>
+ * <p>
+ * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
+ * signer based Policy instance with only a global seinfo tag.
  * </p>
  * <pre>
  * {@code
@@ -504,20 +503,18 @@
  *         .addSignature("308204a8...")
  *         .addSignature("483538c8...")
  *         .setGlobalSeinfoOrThrow("paltform")
- *         .addInnerPackageMapOrThrow("com.foo.", "bar")
- *         .addInnerPackageMapOrThrow("com.foo.other", "bar")
  *         .build();
  * }
  * </pre>
  * <p>
- * An example of how to use {@link Policy.PolicyBuilder} to create a default based Policy
- * instance.
+ * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
+ * default based Policy instance.
  * </p>
  * <pre>
  * {@code
  * Policy policy = new Policy.PolicyBuilder()
  *         .setAsDefaultPolicy()
- *         .setGlobalSeinfoOrThrow("defualt")
+ *         .setGlobalSeinfoOrThrow("default")
  *         .build();
  * }
  * </pre>
@@ -548,6 +545,65 @@
     }
 
     /**
+     * Return whether this policy object represents a default stanza.
+     *
+     * @return A boolean indicating if this object represents a default policy stanza.
+     */
+    public boolean isDefaultStanza() {
+        return mDefaultStanza;
+    }
+
+    /**
+     * Return whether this policy object contains package name mapping refinements.
+     *
+     * @return A boolean indicating if this object has inner package name mappings.
+     */
+    public boolean hasInnerPackages() {
+        return !mPkgMap.isEmpty();
+    }
+
+    /**
+     * Return the mapping of all package name refinements.
+     *
+     * @return A Map object whose keys are the package names and whose values are
+     *         the seinfo assignments.
+     */
+    public Map<String, String> getInnerPackages() {
+        return mPkgMap;
+    }
+
+    /**
+     * Return whether the policy object has a global seinfo tag attached.
+     *
+     * @return A boolean indicating if this stanza has a global seinfo tag.
+     */
+    public boolean hasGlobalSeinfo() {
+        return mSeinfo != null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (mDefaultStanza) {
+            sb.append("defaultStanza=true ");
+        }
+
+        for (Signature cert : mCerts) {
+            sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
+        }
+
+        if (mSeinfo != null) {
+            sb.append("seinfo=" + mSeinfo);
+        }
+
+        for (String name : mPkgMap.keySet()) {
+            sb.append(" " + name + "=" + mPkgMap.get(name));
+        }
+
+        return sb.toString();
+    }
+
+    /**
      * <p>
      * Determine the seinfo value to assign to an apk. The appropriate seinfo value
      * is determined using the following steps:
@@ -620,7 +676,7 @@
         }
 
         /**
-         * Sets this stanza as a defualt stanza. All policy stanzas are assumed to
+         * Sets this stanza as a default stanza. All policy stanzas are assumed to
          * be signer stanzas unless this method is explicitly called. Default stanzas
          * are treated differently with respect to allowable child tags, ordering and
          * when and how policy decisions are enforced.
@@ -754,7 +810,7 @@
          *        <ul>
          *           <li> at least one cert must be found </li>
          *           <li> either a global seinfo value is present OR at least one
-         *           inner package mapping must be present. </li>
+         *           inner package mapping must be present BUT not both. </li>
          *        </ul>
          *      </li>
          *    </ul>
@@ -783,9 +839,9 @@
                     String err = "Missing certs with signer tag. Expecting at least one.";
                     throw new IllegalStateException(err);
                 }
-                if ((p.mSeinfo == null) && (p.mPkgMap.isEmpty())) {
-                    String err = "Missing seinfo OR package tags with signer tag. At " +
-                            "least one must be present.";
+                if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+                    String err = "Only seinfo tag XOR package tags are allowed within " +
+                            "a signer stanza.";
                     throw new IllegalStateException(err);
                 }
             }
@@ -794,3 +850,58 @@
         }
     }
 }
+
+/**
+ * Comparision imposing an ordering on Policy objects. It is understood that Policy
+ * objects can only take one of three forms and ordered according to the following
+ * set of rules most specific to least.
+ * <ul>
+ *   <li> signer stanzas with inner package mappings </li>
+ *   <li> signer stanzas with global seinfo tags </li>
+ *   <li> default stanza </li>
+ * </ul>
+ * This comparison also checks for duplicate entries on the input selectors. Any
+ * found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
+ */
+
+final class PolicyComparator implements Comparator<Policy> {
+
+    private boolean duplicateFound = false;
+
+    public boolean foundDuplicate() {
+        return duplicateFound;
+    }
+
+    @Override
+    public int compare(Policy p1, Policy p2) {
+
+        // Give precedence to signature stanzas over default stanzas
+        if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
+            return p1.isDefaultStanza() ? 1 : -1;
+        }
+
+        // Give precedence to stanzas with inner package mappings
+        if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
+            return p1.hasInnerPackages() ? -1 : 1;
+        }
+
+        // Check for duplicate entries
+        if (p1.getSignatures().equals(p2.getSignatures())) {
+            // Checks if default stanza or a signer w/o inner package names
+            if (p1.hasGlobalSeinfo()) {
+                duplicateFound = true;
+                Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
+            }
+
+            // Look for common inner package name mappings
+            final Map<String, String> p1Packages = p1.getInnerPackages();
+            final Map<String, String> p2Packages = p2.getInnerPackages();
+            if (!Collections.disjoint(p1Packages.keySet(), p2Packages.keySet())) {
+                duplicateFound = true;
+                Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
+            }
+        }
+
+        return 0;
+    }
+}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index 3a7b6ee..0c7f79d 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -24,7 +24,7 @@
     int pkgFlags;
     int pkgPrivateFlags;
 
-    private final PermissionsState mPermissionsState;
+    protected final PermissionsState mPermissionsState;
     private int[] mPermissionsUpdatedForUserIds = PermissionsState.USERS_NONE;
 
     SettingBase(int pkgFlags, int pkgPrivateFlags) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index dd58813..45bfba1 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -22,6 +22,8 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
+import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
@@ -42,18 +44,21 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.VolumeInfo;
 import android.util.AtomicFile;
 import android.text.TextUtils;
 import android.util.LogPrinter;
-
 import android.util.SparseBooleanArray;
 import android.util.SparseLongArray;
+
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
+import com.android.server.backup.PreferredActivityBackupHelper;
 import com.android.server.pm.PackageManagerService.DumpState;
 
 import java.io.FileNotFoundException;
@@ -165,6 +170,8 @@
     static final String TAG_CROSS_PROFILE_INTENT_FILTERS =
             "crossProfile-intent-filters";
     public static final String TAG_DOMAIN_VERIFICATION = "domain-verification";
+    public static final String TAG_DEFAULT_APPS= "default-apps";
+    public static final String TAG_DEFAULT_BROWSER= "default-browser";
 
     private static final String ATTR_NAME = "name";
     private static final String ATTR_USER = "user";
@@ -180,6 +187,7 @@
     private static final String ATTR_INSTALLED = "inst";
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
     private static final String ATTR_DOMAIN_VERIFICATON_STATE = "domainVerificationStatus";
+    private static final String ATTR_PACKAGE_NAME= "packageName";
 
     private final Object mLock;
 
@@ -247,6 +255,8 @@
     // For reading/writing settings file.
     private final ArrayList<Signature> mPastSignatures =
             new ArrayList<Signature>();
+    private final ArrayMap<Long, Integer> mKeySetRefs =
+            new ArrayMap<Long, Integer>();
 
     // Mapping from permission names to info about them.
     final ArrayMap<String, BasePermission> mPermissions =
@@ -265,7 +275,10 @@
     // names.  The packages appear everwhere else under their original
     // names.
     final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
-    
+
+    // For every user, it is used to find the package name of the default Browser App.
+    final SparseArray<String> mDefaultBrowserApp = new SparseArray<String>();
+
     final StringBuilder mReadMessages = new StringBuilder();
 
     /**
@@ -330,14 +343,20 @@
         }
     }
 
-    void setInstallerPackageName(String pkgName,
-            String installerPkgName) {
+    void setInstallerPackageName(String pkgName, String installerPkgName) {
         PackageSetting p = mPackages.get(pkgName);
-        if(p != null) {
+        if (p != null) {
             p.setInstallerPackageName(installerPkgName);
         }
     }
 
+    void setVolumeUuid(String pkgName, String volumeUuid) {
+        PackageSetting p = mPackages.get(pkgName);
+        if (p != null) {
+            p.setVolumeUuid(volumeUuid);
+        }
+    }
+
     SharedUserSetting getSharedUserLPw(String name,
             int pkgFlags, int pkgPrivateFlags, boolean create) {
         SharedUserSetting s = mSharedUsers.get(name);
@@ -953,18 +972,19 @@
     }
 
     /* package protected */
-    boolean createIntentFilterVerificationIfNeededLPw(String packageName, String[] domains) {
+    IntentFilterVerificationInfo createIntentFilterVerificationIfNeededLPw(String packageName,
+            ArrayList<String> domains) {
         PackageSetting ps = mPackages.get(packageName);
         if (ps == null) {
             Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
-            return false;
+            return null;
         }
-        if (ps.getIntentFilterVerificationInfo() == null) {
-            IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(packageName, domains);
+        IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+        if (ivi == null) {
+            ivi = new IntentFilterVerificationInfo(packageName, domains);
             ps.setIntentFilterVerificationInfo(ivi);
-            return false;
         }
-        return true;
+        return ivi;
     }
 
     int getIntentFilterVerificationStatusLPr(String packageName, int userId) {
@@ -983,17 +1003,43 @@
     }
 
     boolean updateIntentFilterVerificationStatusLPw(String packageName, int status, int userId) {
-        PackageSetting ps = mPackages.get(packageName);
-        if (ps == null) {
+        // Update the status for the current package
+        PackageSetting current = mPackages.get(packageName);
+        if (current == null) {
             Slog.w(PackageManagerService.TAG, "No package known for name: " + packageName);
             return false;
         }
-        ps.setDomainVerificationStatusForUser(status, userId);
+        current.setDomainVerificationStatusForUser(status, userId);
+
+        if (current.getIntentFilterVerificationInfo() == null) {
+            Slog.w(PackageManagerService.TAG,
+                    "No IntentFilterVerificationInfo known for name: " + packageName);
+            return false;
+        }
+
+        // Then, if we set a ALWAYS status, then put NEVER status for Apps whose IntentFilter
+        // domains overlap the domains of the current package
+        ArraySet<String> currentDomains = current.getIntentFilterVerificationInfo().getDomainsSet();
+        if (status == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) {
+            for (PackageSetting ps : mPackages.values()) {
+                if (ps == null || ps.pkg.packageName.equals(packageName)) continue;
+                IntentFilterVerificationInfo ivi = ps.getIntentFilterVerificationInfo();
+                if (ivi == null) {
+                    continue;
+                }
+                ArraySet<String> set = ivi.getDomainsSet();
+                set.retainAll(currentDomains);
+                if (set.size() > 0) {
+                    ps.setDomainVerificationStatusForUser(
+                            INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER, userId);
+                }
+            }
+        }
         return true;
     }
 
     /**
-     * Used for dump. Should be read only.
+     * Used for Settings App and PackageManagerService dump. Should be read only.
      */
     List<IntentFilterVerificationInfo> getIntentFilterVerificationsLPr(
             String packageName) {
@@ -1027,6 +1073,19 @@
         }
     }
 
+    boolean setDefaultBrowserPackageNameLPr(String packageName, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            return false;
+        }
+        mDefaultBrowserApp.put(userId, packageName);
+        writePackageRestrictionsLPr(userId);
+        return true;
+    }
+
+    String getDefaultBrowserPackageNameLPw(int userId) {
+        return (userId == UserHandle.USER_ALL) ? null : mDefaultBrowserApp.get(userId);
+    }
+
     private File getUserPackagesStateFile(int userId) {
         // TODO: Implement a cleaner solution when adding tests.
         // This instead of Environment.getUserSystemDirectory(userId) to support testing.
@@ -1106,7 +1165,13 @@
         mExternalDatabaseVersion = CURRENT_DATABASE_VERSION;
     }
 
-    private void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
+    /**
+     * Applies the preferred activity state described by the given XML.  This code
+     * also supports the restore-from-backup code path.
+     *
+     * @see PreferredActivityBackupHelper
+     */
+    void readPreferredActivitiesLPw(XmlPullParser parser, int userId)
             throws XmlPullParserException, IOException {
         int outerDepth = parser.getDepth();
         int type;
@@ -1186,15 +1251,25 @@
         Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName());
     }
 
-    void writeDomainVerificationsLPr(XmlSerializer serializer, String packageName,
-                                     IntentFilterVerificationInfo verificationInfo)
-            throws IllegalArgumentException, IllegalStateException, IOException {
-        if (verificationInfo != null && verificationInfo.getPackageName() != null) {
-            serializer.startTag(null, TAG_DOMAIN_VERIFICATION);
-            verificationInfo.writeToXml(serializer);
-            Log.d(TAG, "Wrote domain verification for package: "
-                    + verificationInfo.getPackageName());
-            serializer.endTag(null, TAG_DOMAIN_VERIFICATION);
+    private void readDefaultAppsLPw(XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals(TAG_DEFAULT_BROWSER)) {
+                String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                mDefaultBrowserApp.put(userId, packageName);
+            } else {
+                String msg = "Unknown element under " +  TAG_DEFAULT_APPS + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
         }
     }
 
@@ -1346,6 +1421,8 @@
                     readPersistentPreferredActivitiesLPw(parser, userId);
                 } else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
                     readCrossProfileIntentFiltersLPw(parser, userId);
+                } else if (tagName.equals(TAG_DEFAULT_APPS)) {
+                    readDefaultAppsLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1397,6 +1474,11 @@
         return components;
     }
 
+    /**
+     * Record the state of preferred activity configuration into XML.  This is used both
+     * for recording packages.xml internally and for supporting backup/restore of the
+     * preferred activity configuration.
+     */
     void writePreferredActivitiesLPr(XmlSerializer serializer, int userId, boolean full)
             throws IllegalArgumentException, IllegalStateException, IOException {
         serializer.startTag(null, "preferred-activities");
@@ -1439,6 +1521,30 @@
         serializer.endTag(null, TAG_CROSS_PROFILE_INTENT_FILTERS);
     }
 
+    void writeDomainVerificationsLPr(XmlSerializer serializer,
+                                     IntentFilterVerificationInfo verificationInfo)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        if (verificationInfo != null && verificationInfo.getPackageName() != null) {
+            serializer.startTag(null, TAG_DOMAIN_VERIFICATION);
+            verificationInfo.writeToXml(serializer);
+            Log.d(TAG, "Wrote domain verification for package: "
+                    + verificationInfo.getPackageName());
+            serializer.endTag(null, TAG_DOMAIN_VERIFICATION);
+        }
+    }
+
+    void writeDefaultAppsLPr(XmlSerializer serializer, int userId)
+            throws IllegalArgumentException, IllegalStateException, IOException {
+        serializer.startTag(null, TAG_DEFAULT_APPS);
+        String packageName = mDefaultBrowserApp.get(userId);
+        if (!TextUtils.isEmpty(packageName)) {
+            serializer.startTag(null, TAG_DEFAULT_BROWSER);
+            serializer.attribute(null, ATTR_PACKAGE_NAME, packageName);
+            serializer.endTag(null, TAG_DEFAULT_BROWSER);
+        }
+        serializer.endTag(null, TAG_DEFAULT_APPS);
+    }
+
     void writePackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -1549,6 +1655,7 @@
             writePreferredActivitiesLPr(serializer, userId, true);
             writePersistentPreferredActivitiesLPr(serializer, userId);
             writeCrossProfileIntentFiltersLPr(serializer, userId);
+            writeDefaultAppsLPr(serializer, userId);
 
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
@@ -2052,39 +2159,33 @@
         if (pkg.installerPackageName != null) {
             serializer.attribute(null, "installer", pkg.installerPackageName);
         }
+        if (pkg.volumeUuid != null) {
+            serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
+        }
         pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
         if ((pkg.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
             writePermissionsLPr(serializer, pkg.getPermissionsState().getInstallPermissions());
         }
 
-        writeSigningKeySetsLPr(serializer, pkg.keySetData);
+        writeSigningKeySetLPr(serializer, pkg.keySetData);
         writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
         writeKeySetAliasesLPr(serializer, pkg.keySetData);
-        writeDomainVerificationsLPr(serializer, pkg.name, pkg.verificationInfo);
+        writeDomainVerificationsLPr(serializer, pkg.verificationInfo);
 
         serializer.endTag(null, "package");
     }
 
-    void writeSigningKeySetsLPr(XmlSerializer serializer,
+    void writeSigningKeySetLPr(XmlSerializer serializer,
             PackageKeySetData data) throws IOException {
-        if (data.getSigningKeySets() != null) {
-            // Keep track of the original signing-keyset.
-            // Must be recorded first, since it will be read first and wipe the
-            // current signing-keysets for the package when set.
-            long properSigningKeySet = data.getProperSigningKeySet();
-            serializer.startTag(null, "proper-signing-keyset");
-            serializer.attribute(null, "identifier", Long.toString(properSigningKeySet));
-            serializer.endTag(null, "proper-signing-keyset");
-            for (long id : data.getSigningKeySets()) {
-                serializer.startTag(null, "signing-keyset");
-                serializer.attribute(null, "identifier", Long.toString(id));
-                serializer.endTag(null, "signing-keyset");
-            }
-        }
+        serializer.startTag(null, "proper-signing-keyset");
+        serializer.attribute(null, "identifier",
+                Long.toString(data.getProperSigningKeySet()));
+        serializer.endTag(null, "proper-signing-keyset");
     }
 
     void writeUpgradeKeySetsLPr(XmlSerializer serializer,
             PackageKeySetData data) throws IOException {
+        long properSigning = data.getProperSigningKeySet();
         if (data.isUsingUpgradeKeySets()) {
             for (long id : data.getUpgradeKeySets()) {
                 serializer.startTag(null, "upgrade-keyset");
@@ -2176,6 +2277,7 @@
 
         mPendingPackages.clear();
         mPastSignatures.clear();
+        mKeySetRefs.clear();
 
         try {
             if (str == null) {
@@ -2237,8 +2339,9 @@
                     // TODO: check whether this is okay! as it is very
                     // similar to how preferred-activities are treated
                     readCrossProfileIntentFiltersLPw(parser, 0);
-                }
-                else if (tagName.equals("updated-package")) {
+                } else if (tagName.equals(TAG_DEFAULT_BROWSER)) {
+                    readDefaultAppsLPw(parser, 0);
+                } else if (tagName.equals("updated-package")) {
                     readDisabledSysPackageLPw(parser);
                 } else if (tagName.equals("cleaning-package")) {
                     String name = parser.getAttributeValue(null, ATTR_NAME);
@@ -2303,7 +2406,7 @@
                     final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
                     mReadExternalStorageEnforced = "1".equals(enforcement);
                 } else if (tagName.equals("keyset-settings")) {
-                    mKeySetManagerService.readKeySetsLPw(parser);
+                    mKeySetManagerService.readKeySetsLPw(parser, mKeySetRefs);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
                             + parser.getName());
@@ -2325,6 +2428,7 @@
         }
 
         final int N = mPendingPackages.size();
+
         for (int i = 0; i < N; i++) {
             final PendingPackage pp = mPendingPackages.get(i);
             Object idObj = getUserIdLPr(pp.sharedId);
@@ -2901,6 +3005,7 @@
         String cpuAbiOverrideString = null;
         String systemStr = null;
         String installerPackageName = null;
+        String volumeUuid = null;
         String uidError = null;
         int pkgFlags = 0;
         int pkgPrivateFlags = 0;
@@ -2938,6 +3043,7 @@
                 }
             }
             installerPackageName = parser.getAttributeValue(null, "installer");
+            volumeUuid = parser.getAttributeValue(null, "volumeUuid");
 
             systemStr = parser.getAttributeValue(null, "publicFlags");
             if (systemStr != null) {
@@ -3086,6 +3192,7 @@
         if (packageSetting != null) {
             packageSetting.uidError = "true".equals(uidError);
             packageSetting.installerPackageName = installerPackageName;
+            packageSetting.volumeUuid = volumeUuid;
             packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr;
             packageSetting.primaryCpuAbiString = primaryCpuAbiString;
             packageSetting.secondaryCpuAbiString = secondaryCpuAbiString;
@@ -3142,16 +3249,27 @@
                     packageSetting.installPermissionsFixed = true;
                 } else if (tagName.equals("proper-signing-keyset")) {
                     long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+                    Integer refCt = mKeySetRefs.get(id);
+                    if (refCt != null) {
+                        mKeySetRefs.put(id, refCt + 1);
+                    } else {
+                        mKeySetRefs.put(id, 1);
+                    }
                     packageSetting.keySetData.setProperSigningKeySet(id);
                 } else if (tagName.equals("signing-keyset")) {
-                    long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
-                    packageSetting.keySetData.addSigningKeySet(id);
+                    // from v1 of keysetmanagerservice - no longer used
                 } else if (tagName.equals("upgrade-keyset")) {
                     long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
                     packageSetting.keySetData.addUpgradeKeySetById(id);
                 } else if (tagName.equals("defined-keyset")) {
                     long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
                     String alias = parser.getAttributeValue(null, "alias");
+                    Integer refCt = mKeySetRefs.get(id);
+                    if (refCt != null) {
+                        mKeySetRefs.put(id, refCt + 1);
+                    } else {
+                        mKeySetRefs.put(id, 1);
+                    }
                     packageSetting.keySetData.addDefinedKeySet(id, alias);
                 } else if (tagName.equals(TAG_DOMAIN_VERIFICATION)) {
                     readDomainVerificationLPw(parser, packageSetting);
@@ -3531,6 +3649,22 @@
         return null;
     }
 
+    /**
+     * Return all {@link PackageSetting} that are actively installed on the
+     * given {@link VolumeInfo#fsUuid}.
+     */
+    List<PackageSetting> getVolumePackagesLPr(String volumeUuid) {
+        Preconditions.checkNotNull(volumeUuid);
+        ArrayList<PackageSetting> res = new ArrayList<>();
+        for (int i = 0; i < mPackages.size(); i++) {
+            final PackageSetting setting = mPackages.valueAt(i);
+            if (Objects.equals(volumeUuid, setting.volumeUuid)) {
+                res.add(setting);
+            }
+        }
+        return res;
+    }
+
     static void printFlags(PrintWriter pw, int val, Object[] spec) {
         pw.print("[ ");
         for (int i=0; i<spec.length; i+=2) {
@@ -3737,6 +3871,10 @@
             pw.print(prefix); pw.print("  installerPackageName=");
                     pw.println(ps.installerPackageName);
         }
+        if (ps.volumeUuid != null) {
+            pw.print(prefix); pw.print("  volumeUuid=");
+                    pw.println(ps.volumeUuid);
+        }
         pw.print(prefix); pw.print("  signatures="); pw.println(ps.signatures);
         pw.print(prefix); pw.print("  installPermissionsFixed=");
                 pw.print(ps.installPermissionsFixed);
@@ -3963,7 +4101,8 @@
 
     void dumpGidsLPr(PrintWriter pw, String prefix, int[] gids) {
         if (!ArrayUtils.isEmpty(gids)) {
-            pw.print(prefix); pw.print("gids="); pw.println(
+            pw.print(prefix);
+            pw.print("gids="); pw.println(
                     PackageManagerService.arrayToString(gids));
         }
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 8cc9d19..e79a2061 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -36,6 +36,7 @@
 import android.os.IUserManager;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -49,9 +50,11 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -71,6 +74,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import libcore.io.IoUtils;
+
 public class UserManagerService extends IUserManager.Stub {
 
     private static final String LOG_TAG = "UserManagerService";
@@ -107,6 +112,8 @@
     private static final String ATTR_TYPE_STRING = "s";
     private static final String ATTR_TYPE_BOOLEAN = "b";
     private static final String ATTR_TYPE_INTEGER = "i";
+    private static final String ATTR_TYPE_BUNDLE = "B";
+    private static final String ATTR_TYPE_BUNDLE_ARRAY = "BA";
 
     private static final String USER_INFO_DIR = "system" + File.separator + "users";
     private static final String USER_LIST_FILENAME = "userlist.xml";
@@ -320,16 +327,20 @@
     public UserInfo getProfileParent(int userHandle) {
         checkManageUsersPermission("get the profile parent");
         synchronized (mPackagesLock) {
-            UserInfo profile = getUserInfoLocked(userHandle);
-            if (profile == null) {
-                return null;
-            }
-            int parentUserId = profile.profileGroupId;
-            if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
-                return null;
-            } else {
-                return getUserInfoLocked(parentUserId);
-            }
+            return getProfileParentLocked(userHandle);
+        }
+    }
+
+    private UserInfo getProfileParentLocked(int userHandle) {
+        UserInfo profile = getUserInfoLocked(userHandle);
+        if (profile == null) {
+            return null;
+        }
+        int parentUserId = profile.profileGroupId;
+        if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
+            return null;
+        } else {
+            return getUserInfoLocked(parentUserId);
         }
     }
 
@@ -1672,124 +1683,171 @@
 
     private Bundle readApplicationRestrictionsLocked(String packageName,
             int userId) {
+        AtomicFile restrictionsFile =
+                new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
+                        packageToRestrictionsFileName(packageName)));
+        return readApplicationRestrictionsLocked(restrictionsFile);
+    }
+
+    @VisibleForTesting
+    static Bundle readApplicationRestrictionsLocked(AtomicFile restrictionsFile) {
         final Bundle restrictions = new Bundle();
-        final ArrayList<String> values = new ArrayList<String>();
+        final ArrayList<String> values = new ArrayList<>();
+        if (!restrictionsFile.getBaseFile().exists()) {
+            return restrictions;
+        }
 
         FileInputStream fis = null;
         try {
-            AtomicFile restrictionsFile =
-                    new AtomicFile(new File(Environment.getUserSystemDirectory(userId),
-                            packageToRestrictionsFileName(packageName)));
             fis = restrictionsFile.openRead();
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(fis, null);
-            int type;
-            while ((type = parser.next()) != XmlPullParser.START_TAG
-                    && type != XmlPullParser.END_DOCUMENT) {
-                ;
-            }
-
-            if (type != XmlPullParser.START_TAG) {
+            XmlUtils.nextElement(parser);
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
                 Slog.e(LOG_TAG, "Unable to read restrictions file "
                         + restrictionsFile.getBaseFile());
                 return restrictions;
             }
-
-            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
-                if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
-                    String key = parser.getAttributeValue(null, ATTR_KEY);
-                    String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
-                    String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
-                    if (multiple != null) {
-                        values.clear();
-                        int count = Integer.parseInt(multiple);
-                        while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
-                            if (type == XmlPullParser.START_TAG
-                                    && parser.getName().equals(TAG_VALUE)) {
-                                values.add(parser.nextText().trim());
-                                count--;
-                            }
-                        }
-                        String [] valueStrings = new String[values.size()];
-                        values.toArray(valueStrings);
-                        restrictions.putStringArray(key, valueStrings);
-                    } else {
-                        String value = parser.nextText().trim();
-                        if (ATTR_TYPE_BOOLEAN.equals(valType)) {
-                            restrictions.putBoolean(key, Boolean.parseBoolean(value));
-                        } else if (ATTR_TYPE_INTEGER.equals(valType)) {
-                            restrictions.putInt(key, Integer.parseInt(value));
-                        } else {
-                            restrictions.putString(key, value);
-                        }
-                    }
-                }
+            while (parser.next() != XmlPullParser.END_DOCUMENT) {
+                readEntry(restrictions, values, parser);
             }
-        } catch (IOException ioe) {
-        } catch (XmlPullParserException pe) {
+        } catch (IOException|XmlPullParserException e) {
+            Log.w(LOG_TAG, "Error parsing " + restrictionsFile.getBaseFile(), e);
         } finally {
-            if (fis != null) {
-                try {
-                    fis.close();
-                } catch (IOException e) {
-                }
-            }
+            IoUtils.closeQuietly(fis);
         }
         return restrictions;
     }
 
+    private static void readEntry(Bundle restrictions, ArrayList<String> values,
+            XmlPullParser parser) throws XmlPullParserException, IOException {
+        int type = parser.getEventType();
+        if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_ENTRY)) {
+            String key = parser.getAttributeValue(null, ATTR_KEY);
+            String valType = parser.getAttributeValue(null, ATTR_VALUE_TYPE);
+            String multiple = parser.getAttributeValue(null, ATTR_MULTIPLE);
+            if (multiple != null) {
+                values.clear();
+                int count = Integer.parseInt(multiple);
+                while (count > 0 && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                    if (type == XmlPullParser.START_TAG
+                            && parser.getName().equals(TAG_VALUE)) {
+                        values.add(parser.nextText().trim());
+                        count--;
+                    }
+                }
+                String [] valueStrings = new String[values.size()];
+                values.toArray(valueStrings);
+                restrictions.putStringArray(key, valueStrings);
+            } else if (ATTR_TYPE_BUNDLE.equals(valType)) {
+                restrictions.putBundle(key, readBundleEntry(parser, values));
+            } else if (ATTR_TYPE_BUNDLE_ARRAY.equals(valType)) {
+                final int outerDepth = parser.getDepth();
+                ArrayList<Bundle> bundleList = new ArrayList<>();
+                while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+                    Bundle childBundle = readBundleEntry(parser, values);
+                    bundleList.add(childBundle);
+                }
+                restrictions.putParcelableArray(key,
+                        bundleList.toArray(new Bundle[bundleList.size()]));
+            } else {
+                String value = parser.nextText().trim();
+                if (ATTR_TYPE_BOOLEAN.equals(valType)) {
+                    restrictions.putBoolean(key, Boolean.parseBoolean(value));
+                } else if (ATTR_TYPE_INTEGER.equals(valType)) {
+                    restrictions.putInt(key, Integer.parseInt(value));
+                } else {
+                    restrictions.putString(key, value);
+                }
+            }
+        }
+    }
+
+    private static Bundle readBundleEntry(XmlPullParser parser, ArrayList<String> values)
+            throws IOException, XmlPullParserException {
+        Bundle childBundle = new Bundle();
+        final int outerDepth = parser.getDepth();
+        while (XmlUtils.nextElementWithin(parser, outerDepth)) {
+            readEntry(childBundle, values, parser);
+        }
+        return childBundle;
+    }
+
     private void writeApplicationRestrictionsLocked(String packageName,
             Bundle restrictions, int userId) {
-        FileOutputStream fos = null;
         AtomicFile restrictionsFile = new AtomicFile(
                 new File(Environment.getUserSystemDirectory(userId),
                         packageToRestrictionsFileName(packageName)));
+        writeApplicationRestrictionsLocked(restrictions, restrictionsFile);
+    }
+
+    @VisibleForTesting
+    static void writeApplicationRestrictionsLocked(Bundle restrictions,
+            AtomicFile restrictionsFile) {
+        FileOutputStream fos = null;
         try {
             fos = restrictionsFile.startWrite();
             final BufferedOutputStream bos = new BufferedOutputStream(fos);
 
-            // XmlSerializer serializer = XmlUtils.serializerInstance();
             final XmlSerializer serializer = new FastXmlSerializer();
             serializer.setOutput(bos, "utf-8");
             serializer.startDocument(null, true);
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
             serializer.startTag(null, TAG_RESTRICTIONS);
-
-            for (String key : restrictions.keySet()) {
-                Object value = restrictions.get(key);
-                serializer.startTag(null, TAG_ENTRY);
-                serializer.attribute(null, ATTR_KEY, key);
-
-                if (value instanceof Boolean) {
-                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
-                    serializer.text(value.toString());
-                } else if (value instanceof Integer) {
-                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_INTEGER);
-                    serializer.text(value.toString());
-                } else if (value == null || value instanceof String) {
-                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
-                    serializer.text(value != null ? (String) value : "");
-                } else {
-                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
-                    String[] values = (String[]) value;
-                    serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
-                    for (String choice : values) {
-                        serializer.startTag(null, TAG_VALUE);
-                        serializer.text(choice != null ? choice : "");
-                        serializer.endTag(null, TAG_VALUE);
-                    }
-                }
-                serializer.endTag(null, TAG_ENTRY);
-            }
-
+            writeBundle(restrictions, serializer);
             serializer.endTag(null, TAG_RESTRICTIONS);
 
             serializer.endDocument();
             restrictionsFile.finishWrite(fos);
         } catch (Exception e) {
             restrictionsFile.failWrite(fos);
-            Slog.e(LOG_TAG, "Error writing application restrictions list");
+            Slog.e(LOG_TAG, "Error writing application restrictions list", e);
+        }
+    }
+
+    private static void writeBundle(Bundle restrictions, XmlSerializer serializer)
+            throws IOException {
+        for (String key : restrictions.keySet()) {
+            Object value = restrictions.get(key);
+            serializer.startTag(null, TAG_ENTRY);
+            serializer.attribute(null, ATTR_KEY, key);
+
+            if (value instanceof Boolean) {
+                serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BOOLEAN);
+                serializer.text(value.toString());
+            } else if (value instanceof Integer) {
+                serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_INTEGER);
+                serializer.text(value.toString());
+            } else if (value == null || value instanceof String) {
+                serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING);
+                serializer.text(value != null ? (String) value : "");
+            } else if (value instanceof Bundle) {
+                serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BUNDLE);
+                writeBundle((Bundle) value, serializer);
+            } else if (value instanceof Parcelable[]) {
+                serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BUNDLE_ARRAY);
+                Parcelable[] array = (Parcelable[]) value;
+                for (Parcelable parcelable : array) {
+                    if (!(parcelable instanceof Bundle)) {
+                        throw new IllegalArgumentException("bundle-array can only hold Bundles");
+                    }
+                    serializer.startTag(null, TAG_ENTRY);
+                    serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_BUNDLE);
+                    writeBundle((Bundle) parcelable, serializer);
+                    serializer.endTag(null, TAG_ENTRY);
+                }
+            } else {
+                serializer.attribute(null, ATTR_VALUE_TYPE, ATTR_TYPE_STRING_ARRAY);
+                String[] values = (String[]) value;
+                serializer.attribute(null, ATTR_MULTIPLE, Integer.toString(values.length));
+                for (String choice : values) {
+                    serializer.startTag(null, TAG_VALUE);
+                    serializer.text(choice != null ? choice : "");
+                    serializer.endTag(null, TAG_VALUE);
+                }
+            }
+            serializer.endTag(null, TAG_ENTRY);
         }
     }
 
@@ -1813,6 +1871,27 @@
         }
     }
 
+    @Override
+    public long getUserCreationTime(int userHandle) {
+        int callingUserId = UserHandle.getCallingUserId();
+        UserInfo userInfo = null;
+        synchronized (mPackagesLock) {
+            if (callingUserId == userHandle) {
+                userInfo = getUserInfoLocked(userHandle);
+            } else {
+                UserInfo parent = getProfileParentLocked(userHandle);
+                if (parent != null && parent.id == callingUserId) {
+                    userInfo = getUserInfoLocked(userHandle);
+                }
+            }
+        }
+        if (userInfo == null) {
+            throw new SecurityException("userHandle can only be the calling user or a managed "
+                    + "profile associated with this user");
+        }
+        return userInfo.creationTime;
+    }
+
     /**
      * Caches the list of user ids in an array, adjusting the array size when necessary.
      */
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index 847eee8..fef1e575 100644
--- a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -27,6 +27,7 @@
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.os.SystemClock;
+import android.util.Slog;
 import android.view.Display;
 import android.view.animation.LinearInterpolator;
 
@@ -45,6 +46,8 @@
     private static final long BURNIN_PROTECTION_WAKEUP_INTERVAL_MS = TimeUnit.MINUTES.toMillis(1);
     private static final long BURNIN_PROTECTION_MINIMAL_INTERVAL_MS = TimeUnit.SECONDS.toMillis(10);
 
+    private static final boolean DEBUG = false;
+
     private static final String ACTION_BURN_IN_PROTECTION =
             "android.internal.policy.action.BURN_IN_PROTECTION";
 
@@ -77,10 +80,13 @@
     private BroadcastReceiver mBurnInProtectionReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Slog.d(TAG, "onReceive " + intent);
+            }
             updateBurnInProtection();
         }
     };
-    
+
     public BurnInProtectionHelper(Context context, int minHorizontalOffset,
             int maxHorizontalOffset, int minVerticalOffset, int maxVerticalOffset,
             int maxOffsetRadius) {
@@ -136,12 +142,26 @@
                 mDisplayManagerInternal.setDisplayOffsets(mDisplay.getDisplayId(),
                         mLastBurnInXOffset, mLastBurnInYOffset);
             }
+            // We use currentTimeMillis to compute the next wakeup time since we want to wake up at
+            // the same time as we wake up to update ambient mode to minimize power consumption.
+            // However, we use elapsedRealtime to schedule the alarm so that setting the time can't
+            // disable burn-in protection for extended periods.
+            final long nowWall = System.currentTimeMillis();
+            final long nowElapsed = SystemClock.elapsedRealtime();
             // Next adjustment at least ten seconds in the future.
-            long next = SystemClock.elapsedRealtime() + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
+            long nextWall = nowWall + BURNIN_PROTECTION_MINIMAL_INTERVAL_MS;
             // And aligned to the minute.
-            next = next - next % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
+            nextWall = nextWall - nextWall % BURNIN_PROTECTION_WAKEUP_INTERVAL_MS
                     + BURNIN_PROTECTION_WAKEUP_INTERVAL_MS;
-            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mBurnInProtectionIntent);
+            // Use elapsed real time that is adjusted to full minute on wall clock.
+            final long nextElapsed = nowElapsed + (nextWall - nowWall);
+            if (DEBUG) {
+                Slog.d(TAG, "scheduling next wake-up, now wall time " + nowWall
+                        + ", next wall: " + nextWall + ", now elapsed: " + nowElapsed
+                        + ", next elapsed: " + nextElapsed);
+            }
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextElapsed,
+                    mBurnInProtectionIntent);
         } else {
             mAlarmManager.cancel(mBurnInProtectionIntent);
             mCenteringAnimator.start();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 87cf06e..936840a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -990,7 +990,7 @@
                     launchHomeFromHotKey();
                     break;
                 case SHORT_PRESS_POWER_GO_HOME:
-                    launchHomeFromHotKey();
+                    launchHomeFromHotKey(true /* awakenFromDreams */, false /*respectKeyguard*/);
                     break;
             }
         }
@@ -1068,7 +1068,7 @@
                         PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
                 break;
             case SHORT_PRESS_SLEEP_GO_TO_SLEEP_AND_GO_HOME:
-                launchHomeFromHotKey(false /* awakenDreams */);
+                launchHomeFromHotKey(false /* awakenDreams */, true /*respectKeyguard*/);
                 mPowerManager.goToSleep(event.getEventTime(),
                         PowerManager.GO_TO_SLEEP_REASON_SLEEP_BUTTON, 0);
                 break;
@@ -1922,6 +1922,7 @@
         case TYPE_PHONE:
             return 3;
         case TYPE_SEARCH_BAR:
+        case TYPE_VOICE_INTERACTION_STARTING:
             return 4;
         case TYPE_VOICE_INTERACTION:
             // voice interaction layer is almost immediately above apps.
@@ -2270,16 +2271,9 @@
                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
                 break;
             case TYPE_NAVIGATION_BAR_PANEL:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                break;
             case TYPE_STATUS_BAR_PANEL:
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.STATUS_BAR_SERVICE,
-                        "PhoneWindowManager");
-                break;
             case TYPE_STATUS_BAR_SUB_PANEL:
+            case TYPE_VOICE_INTERACTION_STARTING:
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.STATUS_BAR_SERVICE,
                         "PhoneWindowManager");
@@ -3065,50 +3059,56 @@
     }
 
     void launchHomeFromHotKey() {
-        launchHomeFromHotKey(true /* awakenFromDreams */);
+        launchHomeFromHotKey(true /* awakenFromDreams */, true /*respectKeyguard*/);
     }
 
     /**
      * A home key -> launch home action was detected.  Take the appropriate action
      * given the situation with the keyguard.
      */
-    void launchHomeFromHotKey(final boolean awakenFromDreams) {
-        if (isKeyguardShowingAndNotOccluded()) {
-            // don't launch home if keyguard showing
-        } else if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
-            // when in keyguard restricted mode, must first verify unlock
-            // before launching home
-            mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
-                @Override
-                public void onKeyguardExitResult(boolean success) {
-                    if (success) {
-                        try {
-                            ActivityManagerNative.getDefault().stopAppSwitches();
-                        } catch (RemoteException e) {
+    void launchHomeFromHotKey(final boolean awakenFromDreams, final boolean respectKeyguard) {
+        if (respectKeyguard) {
+            if (isKeyguardShowingAndNotOccluded()) {
+                // don't launch home if keyguard showing
+                return;
+            }
+
+            if (!mHideLockScreen && mKeyguardDelegate.isInputRestricted()) {
+                // when in keyguard restricted mode, must first verify unlock
+                // before launching home
+                mKeyguardDelegate.verifyUnlock(new OnKeyguardExitResult() {
+                    @Override
+                    public void onKeyguardExitResult(boolean success) {
+                        if (success) {
+                            try {
+                                ActivityManagerNative.getDefault().stopAppSwitches();
+                            } catch (RemoteException e) {
+                            }
+                            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+                            startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
                         }
-                        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                        startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
                     }
-                }
-            });
+                });
+                return;
+            }
+        }
+
+        // no keyguard stuff to worry about, just launch home!
+        try {
+            ActivityManagerNative.getDefault().stopAppSwitches();
+        } catch (RemoteException e) {
+        }
+        if (mRecentsVisible) {
+            // Hide Recents and notify it to launch Home
+            if (awakenFromDreams) {
+                awakenDreams();
+            }
+            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+            hideRecentApps(false, true);
         } else {
-            // no keyguard stuff to worry about, just launch home!
-            try {
-                ActivityManagerNative.getDefault().stopAppSwitches();
-            } catch (RemoteException e) {
-            }
-            if (mRecentsVisible) {
-                // Hide Recents and notify it to launch Home
-                if (awakenFromDreams) {
-                    awakenDreams();
-                }
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                hideRecentApps(false, true);
-            } else {
-                // Otherwise, just launch Home
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
-                startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
-            }
+            // Otherwise, just launch Home
+            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
+            startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
         }
     }
 
@@ -3509,8 +3509,14 @@
     /** {@inheritDoc} */
     @Override
     public int getSystemDecorLayerLw() {
-        if (mStatusBar != null) return mStatusBar.getSurfaceLayer();
-        if (mNavigationBar != null) return mNavigationBar.getSurfaceLayer();
+        if (mStatusBar != null && mStatusBar.isVisibleLw()) {
+            return mStatusBar.getSurfaceLayer();
+        }
+
+        if (mNavigationBar != null && mNavigationBar.isVisibleLw()) {
+            return mNavigationBar.getSurfaceLayer();
+        }
+
         return 0;
     }
 
@@ -3651,7 +3657,7 @@
                 pf.bottom = df.bottom = of.bottom = cf.bottom
                         = mOverscanScreenTop + mOverscanScreenHeight;
             }
-        } else  if (attrs.type == TYPE_INPUT_METHOD || attrs.type == TYPE_VOICE_INTERACTION) {
+        } else if (attrs.type == TYPE_INPUT_METHOD) {
             pf.left = df.left = of.left = cf.left = vf.left = mDockLeft;
             pf.top = df.top = of.top = cf.top = vf.top = mDockTop;
             pf.right = df.right = of.right = cf.right = vf.right = mDockRight;
@@ -3662,6 +3668,15 @@
             // IM dock windows always go to the bottom of the screen.
             attrs.gravity = Gravity.BOTTOM;
             mDockLayer = win.getSurfaceLayer();
+        } else if (attrs.type == TYPE_VOICE_INTERACTION) {
+            pf.left = df.left = of.left = cf.left = vf.left = mUnrestrictedScreenLeft;
+            pf.top = df.top = of.top = mUnrestrictedScreenTop;
+            pf.right = df.right = of.right = cf.right = vf.right = mUnrestrictedScreenLeft
+                    + mUnrestrictedScreenWidth;
+            pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop
+                    + mUnrestrictedScreenHeight;
+            cf.bottom = vf.bottom = mStableBottom;
+            cf.top = vf.top = mStableTop;
         } else if (win == mStatusBar && (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
             pf.left = df.left = of.left = mUnrestrictedScreenLeft;
             pf.top = df.top = of.top = mUnrestrictedScreenTop;
@@ -3901,6 +3916,7 @@
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && (attrs.type == TYPE_STATUS_BAR
                             || attrs.type == TYPE_TOAST
+                            || attrs.type == TYPE_VOICE_INTERACTION_STARTING
                             || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
                     // Asking for layout as if the nav bar is hidden, lets the
diff --git a/services/core/java/com/android/server/power/DeviceIdleController.java b/services/core/java/com/android/server/power/DeviceIdleController.java
index dd00446..a23a87b 100644
--- a/services/core/java/com/android/server/power/DeviceIdleController.java
+++ b/services/core/java/com/android/server/power/DeviceIdleController.java
@@ -377,7 +377,7 @@
         }
     }
 
-    void scheduleAlarmLocked(long delay, boolean wakeup) {
+    void scheduleAlarmLocked(long delay, boolean idleUntil) {
         if (mSigMotionSensor == null) {
             // If there is no significant motion sensor on this device, then we won't schedule
             // alarms, because we can't determine if the device is not moving.  This effectively
@@ -386,8 +386,13 @@
             return;
         }
         mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
-        mAlarmManager.set(wakeup ? AlarmManager.ELAPSED_REALTIME_WAKEUP
-                : AlarmManager.ELAPSED_REALTIME, mNextAlarmTime, mAlarmIntent);
+        if (idleUntil) {
+            mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, mAlarmIntent);
+        } else {
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, mAlarmIntent);
+        }
     }
 
     private void dumpHelp(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 5375bfc..3262cc6 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -204,6 +204,14 @@
             }
 
             @Override
+            public boolean onPackageChanged(String packageName, int uid, String[] components) {
+                // The input list needs to be updated in any cases, regardless of whether
+                // it happened to the whole package or a specific component. Returning true so that
+                // the update can be handled in {@link #onSomePackagesChanged}.
+                return true;
+            }
+
+            @Override
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
                     UserState userState = getUserStateLocked(getChangingUserId());
@@ -1341,6 +1349,108 @@
         }
 
         @Override
+        public void timeShiftPause(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "timeShiftPause");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .timeShiftPause();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in timeShiftPause", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void timeShiftResume(IBinder sessionToken, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "timeShiftResume");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .timeShiftResume();
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in timeShiftResume", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void timeShiftSeekTo(IBinder sessionToken, long timeMs, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "timeShiftSeekTo");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .timeShiftSeekTo(timeMs);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in timeShiftSeekTo", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void timeShiftSetPlaybackRate(IBinder sessionToken, float rate, int audioMode,
+                int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "timeShiftSetPlaybackRate");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .timeShiftSetPlaybackRate(rate, audioMode);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in timeShiftSetPlaybackRate", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
+        public void timeShiftEnablePositionTracking(IBinder sessionToken, boolean enable,
+                int userId) {
+            final int callingUid = Binder.getCallingUid();
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
+                    userId, "timeShiftEnablePositionTracking");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    try {
+                        getSessionLocked(sessionToken, callingUid, resolvedUserId)
+                                .timeShiftEnablePositionTracking(enable);
+                    } catch (RemoteException | SessionNotFoundException e) {
+                        Slog.e(TAG, "error in timeShiftEnablePositionTracking", e);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public List<TvInputHardwareInfo> getHardwareList() throws RemoteException {
             if (mContext.checkCallingPermission(android.Manifest.permission.TV_INPUT_HARDWARE)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -2144,6 +2254,58 @@
                 }
             }
         }
+
+        @Override
+        public void onTimeShiftStatusChanged(int status) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onTimeShiftStatusChanged()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onTimeShiftStatusChanged(status, mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onTimeShiftStatusChanged", e);
+                }
+            }
+        }
+
+        @Override
+        public void onTimeShiftStartPositionChanged(long timeMs) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onTimeShiftStartPositionChanged()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onTimeShiftStartPositionChanged(timeMs, mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onTimeShiftStartPositionChanged", e);
+                }
+            }
+        }
+
+        @Override
+        public void onTimeShiftCurrentPositionChanged(long timeMs) {
+            synchronized (mLock) {
+                if (DEBUG) {
+                    Slog.d(TAG, "onTimeShiftCurrentPositionChanged()");
+                }
+                if (mSessionState.session == null || mSessionState.client == null) {
+                    return;
+                }
+                try {
+                    mSessionState.client.onTimeShiftCurrentPositionChanged(timeMs,
+                            mSessionState.seq);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "error in onTimeShiftCurrentPositionChanged", e);
+                }
+            }
+        }
     }
 
     private static final class WatchLogHandler extends Handler {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index a58f30d..55ec9fc 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -242,7 +242,7 @@
     }
 
     // This must be called while inside a transaction.
-    boolean stepAnimationLocked(long currentTime) {
+    boolean stepAnimationLocked(long currentTime, final int displayId) {
         if (mService.okToDisplay()) {
             // We will run animations as long as the display isn't frozen.
 
@@ -292,7 +292,7 @@
         }
 
         mAnimator.setAppLayoutChanges(this, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                "AppWindowToken");
+                "AppWindowToken", displayId);
 
         clearAnimation();
         animating = false;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index c6951bd..1a125d4 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -24,6 +24,7 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.Message;
@@ -63,6 +64,7 @@
     Display mDisplay;
 
     private final Region mTmpRegion = new Region();
+    private final Rect mTmpRect = new Rect();
 
     DragState(WindowManagerService service, IBinder token, SurfaceControl surface,
             int flags, IBinder localWin) {
@@ -411,6 +413,12 @@
                 continue;
             }
 
+            child.getStackBounds(mTmpRect);
+            if (!mTmpRect.contains(x, y)) {
+                // outside of this window's activity stack == don't tell about drags
+                continue;
+            }
+
             child.getTouchableRegion(mTmpRegion);
 
             final int touchFlags = flags &
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b8f26c9..34120a0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -78,7 +78,7 @@
         }
         if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
-        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
         if (mStack != null) {
             mStack.removeTask(this);
         }
@@ -88,7 +88,7 @@
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
-            EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_REMOVED, mTaskId,
+            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
                     "removeAppToken: last token");
             if (mDeferRemoval) {
                 removeLocked();
@@ -107,6 +107,11 @@
         }
     }
 
+    boolean showWhenLocked() {
+        final int tokensCount = mAppTokens.size();
+        return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showWhenLocked;
+    }
+
     @Override
     public String toString() {
         return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b61a6f7..e845f83 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -275,21 +275,29 @@
         return false;
     }
 
+    void addTask(Task task, boolean toTop) {
+        addTask(task, toTop, task.showWhenLocked());
+    }
+
     /**
      * Put a Task in this stack. Used for adding and moving.
      * @param task The task to add.
      * @param toTop Whether to add it to the top or bottom.
+     * @param showWhenLocked Whether to show the task when the device is locked
+     *                       regardless of the current user.
      */
-    void addTask(Task task, boolean toTop) {
+    void addTask(Task task, boolean toTop, boolean showWhenLocked) {
         int stackNdx;
         if (!toTop) {
             stackNdx = 0;
         } else {
             stackNdx = mTasks.size();
-            if (!mService.isCurrentProfileLocked(task.mUserId)) {
+            if (!showWhenLocked && !mService.isCurrentProfileLocked(task.mUserId)) {
                 // Place the task below all current user tasks.
                 while (--stackNdx >= 0) {
-                    if (!mService.isCurrentProfileLocked(mTasks.get(stackNdx).mUserId)) {
+                    final Task tmpTask = mTasks.get(stackNdx);
+                    if (!tmpTask.showWhenLocked()
+                            || !mService.isCurrentProfileLocked(tmpTask.mUserId)) {
                         break;
                     }
                 }
@@ -490,7 +498,7 @@
         int top = mTasks.size();
         for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
             Task task = mTasks.get(taskNdx);
-            if (mService.isCurrentProfileLocked(task.mUserId)) {
+            if (mService.isCurrentProfileLocked(task.mUserId) || task.showWhenLocked()) {
                 mTasks.remove(taskNdx);
                 mTasks.add(task);
                 --top;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 46fa38a..897b865 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -159,13 +159,13 @@
                     final AppWindowAnimator appAnimator = tokens.get(tokenNdx).mAppAnimator;
                     final boolean wasAnimating = appAnimator.animation != null
                             && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-                    if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                    if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
                         mAnimating = mAppWindowAnimating = true;
                     } else if (wasAnimating) {
                         // stopped animating, do one more pass through the layout
                         setAppLayoutChanges(appAnimator,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                "appToken " + appAnimator.mAppToken + " done");
+                                "appToken " + appAnimator.mAppToken + " done", displayId);
                         if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                                 "updateWindowsApps...: done animating " + appAnimator.mAppToken);
                     }
@@ -178,12 +178,12 @@
                 final AppWindowAnimator appAnimator = exitingAppTokens.get(i).mAppAnimator;
                 final boolean wasAnimating = appAnimator.animation != null
                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
-                if (appAnimator.stepAnimationLocked(mCurrentTime)) {
+                if (appAnimator.stepAnimationLocked(mCurrentTime, displayId)) {
                     mAnimating = mAppWindowAnimating = true;
                 } else if (wasAnimating) {
                     // stopped animating, do one more pass through the layout
                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                        "exiting appToken " + appAnimator.mAppToken + " done");
+                        "exiting appToken " + appAnimator.mAppToken + " done", displayId);
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
                             "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
                 }
@@ -575,11 +575,11 @@
                             // This will set mOrientationChangeComplete and cause a pass through layout.
                             setAppLayoutChanges(appAnimator,
                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                                    "testTokenMayBeDrawnLocked: freezingScreen");
+                                    "testTokenMayBeDrawnLocked: freezingScreen", displayId);
                         } else {
                             setAppLayoutChanges(appAnimator,
                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM,
-                                    "testTokenMayBeDrawnLocked");
+                                    "testTokenMayBeDrawnLocked", displayId);
 
                             // We can now show all of the drawn windows!
                             if (!mService.mOpeningApps.contains(wtoken)) {
@@ -792,28 +792,30 @@
         if (displayId < 0) {
             return 0;
         }
-        return mService.getDisplayContentLocked(displayId).pendingLayoutChanges;
+        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
     }
 
     void setPendingLayoutChanges(final int displayId, final int changes) {
-        if (displayId >= 0) {
-            mService.getDisplayContentLocked(displayId).pendingLayoutChanges |= changes;
+        if (displayId < 0) {
+            return;
+        }
+        final DisplayContent displayContent = mService.getDisplayContentLocked(displayId);
+        if (displayContent != null) {
+            displayContent.pendingLayoutChanges |= changes;
         }
     }
 
-    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String s) {
-        // Used to track which displays layout changes have been done.
-        SparseIntArray displays = new SparseIntArray(2);
+    void setAppLayoutChanges(final AppWindowAnimator appAnimator, final int changes, String reason,
+            final int displayId) {
         WindowList windows = appAnimator.mAppToken.allAppWindows;
         for (int i = windows.size() - 1; i >= 0; i--) {
-            final int displayId = windows.get(i).getDisplayId();
-            if (displayId >= 0 && displays.indexOfKey(displayId) < 0) {
+            if (displayId == windows.get(i).getDisplayId()) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats(s, getPendingLayoutChanges(displayId));
+                    mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
                 }
-                // Keep from processing this display again.
-                displays.put(displayId, changes);
+                break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dcd233f..e790fb0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -178,7 +178,7 @@
     static final boolean DEBUG_ORIENTATION = false;
     static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
-    static final boolean DEBUG_APP_TRANSITIONS = true;
+    static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
@@ -189,7 +189,7 @@
     static final boolean DEBUG_LAYOUT_REPEATS = true;
     static final boolean DEBUG_SURFACE_TRACE = false;
     static final boolean DEBUG_WINDOW_TRACE = false;
-    static final boolean DEBUG_TASK_MOVEMENT = true;
+    static final boolean DEBUG_TASK_MOVEMENT = false;
     static final boolean DEBUG_STACK = false;
     static final boolean DEBUG_DISPLAY = false;
     static final boolean DEBUG_POWER = false;
@@ -617,8 +617,8 @@
     static final long WALLPAPER_TIMEOUT_RECOVERY = 10000;
     boolean mAnimateWallpaperWithTarget;
 
-    // We give a wallpaper up to 1000ms to finish drawing before playing app transitions.
-    static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 1000;
+    // We give a wallpaper up to 500ms to finish drawing before playing app transitions.
+    static final long WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION = 500;
     static final int WALLPAPER_DRAW_NORMAL = 0;
     static final int WALLPAPER_DRAW_PENDING = 1;
     static final int WALLPAPER_DRAW_TIMEOUT = 2;
@@ -3056,7 +3056,7 @@
                 }
             }
 
-            if (true || DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
+            if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
                     + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
 
             win.mEnforceSizeCompat =
@@ -3620,7 +3620,7 @@
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
         Task task = new Task(taskId, stack, userId, this);
         mTaskIdToTask.put(taskId, task);
-        stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */);
+        stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showWhenLocked);
         return task;
     }
 
@@ -4610,19 +4610,24 @@
                     " hidden=" + wtoken.hidden + " hiddenRequested=" +
                     wtoken.hiddenRequested + " Callers=" + Debug.getCallers(6));
 
+            mOpeningApps.remove(wtoken);
+            mClosingApps.remove(wtoken);
+            wtoken.waitingToShow = wtoken.waitingToHide = false;
+            wtoken.hiddenRequested = !visible;
+
+            mOpeningApps.remove(wtoken);
+            mClosingApps.remove(wtoken);
+            wtoken.waitingToShow = wtoken.waitingToHide = false;
+            wtoken.hiddenRequested = !visible;
+
             // If we are preparing an app transition, then delay changing
             // the visibility of this token until we execute that transition.
             if (okToDisplay() && mAppTransition.isTransitionSet()) {
-                wtoken.hiddenRequested = !visible;
-
                 if (!wtoken.startingDisplayed) {
                     if (DEBUG_APP_TRANSITIONS) Slog.v(
                             TAG, "Setting dummy animation on: " + wtoken);
                     wtoken.mAppAnimator.setDummyAnimation();
                 }
-                mOpeningApps.remove(wtoken);
-                mClosingApps.remove(wtoken);
-                wtoken.waitingToShow = wtoken.waitingToHide = false;
                 wtoken.inPendingTransaction = true;
                 if (visible) {
                     mOpeningApps.add(wtoken);
@@ -4696,7 +4701,8 @@
                 WindowState w = wtoken.allAppWindows.get(i);
                 if (w.mAppFreezing) {
                     w.mAppFreezing = false;
-                    if (w.mHasSurface && !w.mOrientationChanging) {
+                    if (w.mHasSurface && !w.mOrientationChanging
+                            && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
                         if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
                         w.mOrientationChanging = true;
                         mInnerFields.mOrientationChangeComplete = false;
@@ -9016,7 +9022,7 @@
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
         // orientation.
-        if (!okToDisplay()) {
+        if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
@@ -9059,41 +9065,40 @@
                     goodToGo = false;
                 }
             }
-// Stuck in a state with mWallpaperDrawState == WALLPAPER_DRAW_PENDING without a timeout. Leave
-// commented out until that is understood.
-//            if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
-//                boolean wallpaperGoodToGo = true;
-//                for (int curTokenIndex = mWallpaperTokens.size() - 1;
-//                        curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
-//                    WindowToken token = mWallpaperTokens.get(curTokenIndex);
-//                    for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
-//                            curWallpaperIndex--) {
-//                        WindowState wallpaper = token.windows.get(curWallpaperIndex);
-//                        if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
-//                            // We've told this wallpaper to be visible, but it is not drawn yet
-//                            wallpaperGoodToGo = false;
-//                            if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
-//                                // wait for this wallpaper until it is drawn or timeout
-//                                goodToGo = false;
-//                            }
-//                            if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
-//                                mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
-//                                mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
-//                                mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
-//                                        WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
-//                            }
-//                            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
-//                                    "Wallpaper should be visible but has not been drawn yet. " +
-//                                    "mWallpaperDrawState=" + mWallpaperDrawState);
-//                            break;
-//                        }
-//                    }
-//                }
-//                if (wallpaperGoodToGo) {
-//                    mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
-//                    mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
-//                }
-//            }
+
+            if (goodToGo && isWallpaperVisible(mWallpaperTarget)) {
+                boolean wallpaperGoodToGo = true;
+                for (int curTokenIndex = mWallpaperTokens.size() - 1;
+                        curTokenIndex >= 0 && wallpaperGoodToGo; curTokenIndex--) {
+                    WindowToken token = mWallpaperTokens.get(curTokenIndex);
+                    for (int curWallpaperIndex = token.windows.size() - 1; curWallpaperIndex >= 0;
+                            curWallpaperIndex--) {
+                        WindowState wallpaper = token.windows.get(curWallpaperIndex);
+                        if (wallpaper.mWallpaperVisible && !wallpaper.isDrawnLw()) {
+                            // We've told this wallpaper to be visible, but it is not drawn yet
+                            wallpaperGoodToGo = false;
+                            if (mWallpaperDrawState != WALLPAPER_DRAW_TIMEOUT) {
+                                // wait for this wallpaper until it is drawn or timeout
+                                goodToGo = false;
+                            }
+                            if (mWallpaperDrawState == WALLPAPER_DRAW_NORMAL) {
+                                mWallpaperDrawState = WALLPAPER_DRAW_PENDING;
+                                mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
+                                mH.sendEmptyMessageDelayed(H.WALLPAPER_DRAW_PENDING_TIMEOUT,
+                                        WALLPAPER_DRAW_PENDING_TIMEOUT_DURATION);
+                            }
+                            if (DEBUG_APP_TRANSITIONS || DEBUG_WALLPAPER) Slog.v(TAG,
+                                    "Wallpaper should be visible but has not been drawn yet. " +
+                                    "mWallpaperDrawState=" + mWallpaperDrawState);
+                            break;
+                        }
+                    }
+                }
+                if (wallpaperGoodToGo) {
+                    mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
+                    mH.removeMessages(H.WALLPAPER_DRAW_PENDING_TIMEOUT);
+                }
+            }
         }
         if (goodToGo) {
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index f94ed77..db3268d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1490,6 +1490,11 @@
             mOrientationChanging = false;
             mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                     - mService.mDisplayFreezeTime);
+            // We are assuming the hosting process is dead or in a zombie state.
+            Slog.w(TAG, "Failed to report 'resized' to the client of " + this
+                    + ", removing this window.");
+            mService.mPendingRemove.add(this);
+            mService.requestTraversalLocked();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ac1b0f1..1a30cba 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1403,6 +1403,9 @@
                 if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
                         "SIZE " + width + "x" + height, null);
                 mSurfaceControl.setSize(width, height);
+                mSurfaceControl.setMatrix(
+                        mDsDx * w.mHScale, mDtDx * w.mVScale,
+                        mDsDy * w.mHScale, mDtDy * w.mVScale);
                 mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                 if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 7b74e91..6448de2 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -10,6 +10,7 @@
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_fingerprint_FingerprintService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
diff --git a/core/jni/android_server_FingerprintManager.cpp b/services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
similarity index 100%
rename from core/jni/android_server_FingerprintManager.cpp
rename to services/core/jni/com_android_server_fingerprint_FingerprintService.cpp
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index 049e455..d5508bc 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -297,6 +297,14 @@
       getSourcesToUse
       );
 
+  jmethodID getSmallestDisplacementMeters = env->GetMethodID(
+      batchOptionsClass,
+      "getSmallestDisplacementMeters",
+      "()F"
+      );
+  batchOptions.smallest_displacement_meters
+      = env->CallFloatMethod(batchOptionsObject, getSmallestDisplacementMeters);
+
   jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
   batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index ea59d4b..c766183 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -110,9 +110,9 @@
     /**
      * Creates an instance of the device owner object with the device initializer set.
      */
-    static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) {
+    static DeviceOwner createWithDeviceInitializer(ComponentName admin, String ownerName) {
         DeviceOwner owner = new DeviceOwner();
-        owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+        owner.mDeviceInitializer = new OwnerInfo(ownerName, admin);
         return owner;
     }
 
@@ -141,6 +141,10 @@
         mDeviceOwner = null;
     }
 
+    ComponentName getDeviceInitializerComponent() {
+        return mDeviceInitializer.admin;
+    }
+
     String getDeviceInitializerPackageName() {
         return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
     }
@@ -149,8 +153,8 @@
         return mDeviceInitializer != null ? mDeviceInitializer.name : null;
     }
 
-    void setDeviceInitializer(String packageName, String ownerName) {
-        mDeviceInitializer = new OwnerInfo(ownerName, packageName);
+    void setDeviceInitializer(ComponentName admin, String ownerName) {
+        mDeviceInitializer = new OwnerInfo(ownerName, admin);
     }
 
     void clearDeviceInitializer() {
@@ -235,7 +239,17 @@
                 } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
                     String name = parser.getAttributeValue(null, ATTR_NAME);
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    mDeviceInitializer = new OwnerInfo(name, packageName);
+                    String initializerComponentStr =
+                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
+                    ComponentName admin =
+                            ComponentName.unflattenFromString(initializerComponentStr);
+                    if (admin != null) {
+                        mDeviceInitializer = new OwnerInfo(name, admin);
+                    } else {
+                        mDeviceInitializer = new OwnerInfo(name, packageName);
+                        Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
+                                initializerComponentStr);
+                    }
                 } else if (tag.equals(TAG_PROFILE_OWNER)) {
                     String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
                     String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -303,6 +317,10 @@
                 if (mDeviceInitializer.name != null) {
                     out.attribute(null, ATTR_NAME, mDeviceInitializer.name);
                 }
+                if (mDeviceInitializer.admin != null) {
+                    out.attribute(
+                            null, ATTR_COMPONENT_NAME, mDeviceInitializer.admin.flattenToString());
+                }
                 out.endTag(null, TAG_DEVICE_INITIALIZER);
             }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0c58aef..bb3085e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -280,15 +280,12 @@
         long mLastMaximumTimeToLock = -1;
         boolean mUserSetupComplete = false;
 
-        final HashMap<ComponentName, ActiveAdmin> mAdminMap
-                = new HashMap<ComponentName, ActiveAdmin>();
-        final ArrayList<ActiveAdmin> mAdminList
-                = new ArrayList<ActiveAdmin>();
-        final ArrayList<ComponentName> mRemovingAdmins
-                = new ArrayList<ComponentName>();
+        final HashMap<ComponentName, ActiveAdmin> mAdminMap = new HashMap<>();
+        final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
+        final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
 
         // This is the list of component allowed to start lock task mode.
-        final List<String> mLockTaskPackages = new ArrayList<String>();
+        final List<String> mLockTaskPackages = new ArrayList<>();
 
         ComponentName mRestrictionsProvider;
 
@@ -299,7 +296,7 @@
         }
     }
 
-    final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>();
+    final SparseArray<DevicePolicyData> mUserData = new SparseArray<>();
 
     Handler mHandler = new Handler();
 
@@ -1596,6 +1593,16 @@
         validatePasswordOwnerLocked(policy);
         syncDeviceCapabilitiesLocked(policy);
         updateMaximumTimeToLockLocked(policy);
+        updateLockTaskPackagesLocked(policy, userHandle);
+    }
+
+    private void updateLockTaskPackagesLocked(DevicePolicyData policy, int userId) {
+        IActivityManager am = ActivityManagerNative.getDefault();
+        try {
+            am.updateLockTaskPackages(userId, policy.mLockTaskPackages.toArray(new String[0]));
+        } catch (RemoteException e) {
+            // Not gonna happen.
+        }
     }
 
     static void validateQualityConstant(int quality) {
@@ -3125,6 +3132,8 @@
     }
 
     private void wipeDataLocked(boolean wipeExtRequested, String reason) {
+        // TODO: wipe all public volumes on device
+
         // If the SD card is encrypted and non-removable, we have to force a wipe.
         boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
 
@@ -4007,12 +4016,12 @@
             if (mDeviceOwner == null) {
                 // Device owner state does not exist, create it.
                 mDeviceOwner = DeviceOwner.createWithDeviceInitializer(
-                        initializer.getPackageName(), ownerName);
+                        initializer, ownerName);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             } else {
                 // Device owner already exists, update it.
-                mDeviceOwner.setDeviceInitializer(initializer.getPackageName(), ownerName);
+                mDeviceOwner.setDeviceInitializer(initializer, ownerName);
                 mDeviceOwner.writeOwnerFile();
                 return true;
             }
@@ -4058,6 +4067,19 @@
     }
 
     @Override
+    public ComponentName getDeviceInitializerComponent() {
+        if (!mHasFeature) {
+            return null;
+        }
+        synchronized (this) {
+            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+                return mDeviceOwner.getDeviceInitializerComponent();
+            }
+        }
+        return null;
+    }
+
+    @Override
     public void clearDeviceInitializer(ComponentName who) {
         if (!mHasFeature) {
             return;
@@ -5050,7 +5072,10 @@
 
             long id = Binder.clearCallingIdentity();
             try {
-                return mUserManager.getApplicationRestrictions(packageName, userHandle);
+                Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
+                // if no restrictions were saved, mUserManager.getApplicationRestrictions
+                // returns null, but DPM method should return an empty Bundle as per JavaDoc
+                return bundle != null ? bundle : Bundle.EMPTY;
             } finally {
                 restoreCallingIdentity(id);
             }
@@ -5515,6 +5540,7 @@
 
             // Store the settings persistently.
             saveSettingsLocked(userHandle);
+            updateLockTaskPackagesLocked(policy, userHandle);
         }
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 090c0f8..53da75b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -53,6 +53,7 @@
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.audio.AudioService;
+import com.android.server.camera.CameraService;
 import com.android.server.clipboard.ClipboardService;
 import com.android.server.content.ContentService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
@@ -408,6 +409,7 @@
         AudioService audioService = null;
         MmsServiceBroker mmsService = null;
         EntropyMixer entropyMixer = null;
+        CameraService cameraService = null;
 
         boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
         boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
@@ -436,6 +438,9 @@
 
             mContentResolver = context.getContentResolver();
 
+            Slog.i(TAG, "Camera Service");
+            mSystemServiceManager.startService(CameraService.class);
+
             // The AccountManager must come before the ContentService
             try {
                 // TODO: seems like this should be disable-able, but req'd by ContentService
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 1d2180e..c1c5c56 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -372,8 +372,8 @@
             int numOutputPorts, String[] inputPortNames, String[] outputPortNames,
             Bundle properties, int type) {
         int uid = Binder.getCallingUid();
-        if (type != MidiDeviceInfo.TYPE_VIRTUAL && uid != Process.SYSTEM_UID) {
-            throw new SecurityException("only system can create non-virtual devices");
+        if (type == MidiDeviceInfo.TYPE_USB && uid != Process.SYSTEM_UID) {
+            throw new SecurityException("only system can create USB devices");
         }
 
         synchronized (mDevicesByInfo) {
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a232a6e..d41629d 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -611,10 +611,22 @@
     /**
      * Reads a string of specified length from the buffer.
      */
-    private static String readAsciiString(ByteBuffer buf, int byteCount) {
+    private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) {
         byte[] bytes = new byte[byteCount];
         buf.get(bytes);
-        return new String(bytes, 0, bytes.length, StandardCharsets.US_ASCII);
+        int length = bytes.length;
+        if (!nullOk) {
+            // Stop at the first null byte. This is because some DHCP options (e.g., the domain
+            // name) are passed to netd via FrameworkListener, which refuses arguments containing
+            // null bytes. We don't do this by default because vendorInfo is an opaque string which
+            // could in theory contain null bytes.
+            for (length = 0; length < bytes.length; length++) {
+                if (bytes[length] == 0) {
+                    break;
+                }
+            }
+        }
+        return new String(bytes, 0, length, StandardCharsets.US_ASCII);
     }
 
     /**
@@ -797,7 +809,7 @@
                             break;
                         case DHCP_HOST_NAME:
                             expectedLen = optionLen;
-                            hostName = readAsciiString(packet, optionLen);
+                            hostName = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_MTU:
                             expectedLen = 2;
@@ -805,7 +817,7 @@
                             break;
                         case DHCP_DOMAIN_NAME:
                             expectedLen = optionLen;
-                            domainName = readAsciiString(packet, optionLen);
+                            domainName = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_BROADCAST_ADDRESS:
                             bcAddr = readIpAddress(packet);
@@ -834,7 +846,7 @@
                             break;
                         case DHCP_MESSAGE:
                             expectedLen = optionLen;
-                            message = readAsciiString(packet, optionLen);
+                            message = readAsciiString(packet, optionLen, false);
                             break;
                         case DHCP_MAX_MESSAGE_SIZE:
                             expectedLen = 2;
@@ -850,7 +862,7 @@
                             break;
                         case DHCP_VENDOR_CLASS_ID:
                             expectedLen = optionLen;
-                            vendorId = readAsciiString(packet, optionLen);
+                            vendorId = readAsciiString(packet, optionLen, true);
                             break;
                         case DHCP_CLIENT_IDENTIFIER: { // Client identifier
                             byte[] id = new byte[optionLen];
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 33edb11..ae19dac 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -204,8 +204,8 @@
 
             IntentSender intentSender = PendingIntent.getActivityAsUser(
                     mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
-                    | PendingIntent.FLAG_CANCEL_CURRENT, null, new UserHandle(mUserId))
-                    .getIntentSender();
+                    | PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
+                    null, new UserHandle(mUserId)) .getIntentSender();
 
             Bundle result = new Bundle();
             result.putParcelable(PrintManager.EXTRA_PRINT_JOB, printJob);
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index f25fc62..33979b1 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -10,6 +10,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     services.core \
     services.devicepolicy \
+    services.net \
     easymocklib \
     guava \
     mockito-target
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
new file mode 100644
index 0000000..2658937
--- /dev/null
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dhcp;
+
+import android.net.NetworkUtils;
+import android.system.OsConstants;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.net.Inet4Address;
+import java.nio.ByteBuffer;
+
+import static android.net.dhcp.DhcpPacket.*;
+
+
+public class DhcpPacketTest extends TestCase {
+
+    private static Inet4Address SERVER_ADDR =
+            (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.1");
+    private static Inet4Address CLIENT_ADDR =
+            (Inet4Address) NetworkUtils.numericToInetAddress("192.0.2.234");
+    private static byte[] CLIENT_MAC = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+
+    class TestDhcpPacket extends DhcpPacket {
+        private byte mType;
+        // TODO: Make this a map of option numbers to bytes instead.
+        private byte[] mDomainBytes, mVendorInfoBytes;
+
+        public TestDhcpPacket(byte type, byte[] domainBytes, byte[] vendorInfoBytes) {
+            super(0xdeadbeef, INADDR_ANY, CLIENT_ADDR, INADDR_ANY, INADDR_ANY, CLIENT_MAC, true);
+            mType = type;
+            mDomainBytes = domainBytes;
+            mVendorInfoBytes = vendorInfoBytes;
+        }
+
+        public ByteBuffer buildPacket(int encap, short unusedDestUdp, short unusedSrcUdp) {
+            ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
+            fillInPacket(encap, CLIENT_ADDR, SERVER_ADDR,
+                         DHCP_CLIENT, DHCP_SERVER, result, DHCP_BOOTREPLY, false);
+            return result;
+        }
+
+        public void finishPacket(ByteBuffer buffer) {
+            addTlv(buffer, DHCP_MESSAGE_TYPE, mType);
+            if (mDomainBytes != null) {
+                addTlv(buffer, DHCP_DOMAIN_NAME, mDomainBytes);
+            }
+            if (mVendorInfoBytes != null) {
+                addTlv(buffer, DHCP_VENDOR_CLASS_ID, mVendorInfoBytes);
+            }
+            addTlvEnd(buffer);
+        }
+
+        // Convenience method.
+        public ByteBuffer build() {
+            // ENCAP_BOOTP packets don't contain ports, so just pass in 0.
+            ByteBuffer pkt = buildPacket(ENCAP_BOOTP, (short) 0, (short) 0);
+            pkt.flip();
+            return pkt;
+        }
+    }
+
+    private void assertDomainAndVendorInfoParses(
+            String expectedDomain, byte[] domainBytes,
+            String expectedVendorInfo, byte[] vendorInfoBytes) {
+        ByteBuffer packet = new TestDhcpPacket(DHCP_MESSAGE_TYPE_OFFER,
+                domainBytes, vendorInfoBytes).build();
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_BOOTP);
+        assertEquals(expectedDomain, offerPacket.mDomainName);
+        assertEquals(expectedVendorInfo, offerPacket.mVendorId);
+    }
+
+    @SmallTest
+    public void testDomainName() throws Exception {
+        byte[] nullByte = new byte[] { 0x00 };
+        byte[] twoNullBytes = new byte[] { 0x00, 0x00 };
+        byte[] nonNullDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l'
+        };
+        byte[] trailingNullDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', (byte) '.', (byte) 'g', (byte) 'l', 0x00
+        };
+        byte[] embeddedNullsDomain = new byte[] {
+            (byte) 'g', (byte) 'o', (byte) 'o', 0x00, 0x00, (byte) 'g', (byte) 'l'
+        };
+        byte[] metered = "ANDROID_METERED".getBytes("US-ASCII");
+
+        byte[] meteredEmbeddedNull = metered.clone();
+        meteredEmbeddedNull[7] = (char) 0;
+
+        byte[] meteredTrailingNull = metered.clone();
+        meteredTrailingNull[meteredTrailingNull.length - 1] = (char) 0;
+
+        assertDomainAndVendorInfoParses("", nullByte, "\u0000", nullByte);
+        assertDomainAndVendorInfoParses("", twoNullBytes, "\u0000\u0000", twoNullBytes);
+        assertDomainAndVendorInfoParses("goo.gl", nonNullDomain, "ANDROID_METERED", metered);
+        assertDomainAndVendorInfoParses("goo", embeddedNullsDomain,
+                                        "ANDROID\u0000METERED", meteredEmbeddedNull);
+        assertDomainAndVendorInfoParses("goo.gl", trailingNullDomain,
+                                        "ANDROID_METERE\u0000", meteredTrailingNull);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 7383478..7ea5aa7 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -39,6 +39,7 @@
 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
 import static android.text.format.DateUtils.WEEK_IN_MILLIS;
 import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL;
+import static org.easymock.EasyMock.anyInt;
 import static org.easymock.EasyMock.anyLong;
 import static org.easymock.EasyMock.capture;
 import static org.easymock.EasyMock.createMock;
@@ -879,7 +880,7 @@
         expectLastCall().anyTimes();
 
         mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
-                isA(PendingIntent.class), isA(WorkSource.class),
+                anyInt(), isA(PendingIntent.class), isA(WorkSource.class),
                 isA(AlarmManager.AlarmClockInfo.class));
         expectLastCall().atLeastOnce();
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
new file mode 100644
index 0000000..eb7eb15
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.pm;
+
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Parcelable;
+import android.test.AndroidTestCase;
+import android.util.AtomicFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class UserManagerServiceTest extends AndroidTestCase {
+    private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
+    private File restrictionsFile;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        restrictionsFile = new File(mContext.getCacheDir(), "restrictions.xml");
+        restrictionsFile.delete();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        restrictionsFile.delete();
+        super.tearDown();
+    }
+
+    public void testWriteReadApplicationRestrictions() throws IOException {
+        AtomicFile atomicFile = new AtomicFile(restrictionsFile);
+        Bundle bundle = createBundle();
+        UserManagerService.writeApplicationRestrictionsLocked(bundle, atomicFile);
+        assertTrue(atomicFile.getBaseFile().exists());
+        String s = FileUtils.readTextFile(restrictionsFile, 10000, "");
+        System.out.println("restrictionsFile: " + s);
+        bundle = UserManagerService.readApplicationRestrictionsLocked(atomicFile);
+        System.out.println("readApplicationRestrictionsLocked bundle: " + bundle);
+        assertBundle(bundle);
+    }
+
+    private Bundle createBundle() {
+        Bundle result = new Bundle();
+        // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
+        result.putBoolean("boolean_0", false);
+        result.putBoolean("boolean_1", true);
+        result.putInt("integer", 100);
+        result.putString("empty", "");
+        result.putString("string", "text");
+        result.putStringArray("string[]", STRING_ARRAY);
+
+        Bundle bundle = new Bundle();
+        bundle.putString("bundle_string", "bundle_string");
+        bundle.putInt("bundle_int", 1);
+        result.putBundle("bundle", bundle);
+
+        Bundle[] bundleArray = new Bundle[2];
+        bundleArray[0] = new Bundle();
+        bundleArray[0].putString("bundle_array_string", "bundle_array_string");
+        bundleArray[0].putBundle("bundle_array_bundle", bundle);
+        bundleArray[1] = new Bundle();
+        bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
+        result.putParcelableArray("bundle_array", bundleArray);
+        return result;
+    }
+
+    private void assertBundle(Bundle bundle) {
+        assertFalse(bundle.getBoolean("boolean_0"));
+        assertTrue(bundle.getBoolean("boolean_1"));
+        assertEquals(100, bundle.getInt("integer"));
+        assertEquals("", bundle.getString("empty"));
+        assertEquals("text", bundle.getString("string"));
+        assertEquals(Arrays.asList(STRING_ARRAY), Arrays.asList(bundle.getStringArray("string[]")));
+        Parcelable[] bundle_array = bundle.getParcelableArray("bundle_array");
+        assertEquals(2, bundle_array.length);
+        Bundle bundle1 = (Bundle) bundle_array[0];
+        assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
+        assertNotNull(bundle1.getBundle("bundle_array_bundle"));
+        Bundle bundle2 = (Bundle) bundle_array[1];
+        assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
+        Bundle childBundle = bundle.getBundle("bundle");
+        assertEquals("bundle_string", childBundle.getString("bundle_string"));
+        assertEquals(1, childBundle.getInt("bundle_int"));
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index a0b8c94..bfa308e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -32,8 +32,9 @@
 /** Test {@link UserManager} functionality. */
 public class UserManagerTest extends AndroidTestCase {
 
-    UserManager mUserManager = null;
-    Object mUserLock = new Object();
+    private UserManager mUserManager = null;
+    private final Object mUserLock = new Object();
+    private List<Integer> usersToRemove;
 
     @Override
     public void setUp() throws Exception {
@@ -49,11 +50,19 @@
         }, filter);
 
         removeExistingUsers();
+        usersToRemove = new ArrayList<>();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        for (Integer userId : usersToRemove) {
+            removeUser(userId);
+        }
+        super.tearDown();
     }
 
     private void removeExistingUsers() {
         List<UserInfo> list = mUserManager.getUsers();
-        boolean found = false;
         for (UserInfo user : list) {
             if (user.id != UserHandle.USER_OWNER) {
                 removeUser(user.id);
@@ -66,7 +75,7 @@
     }
 
     public void testAddUser() throws Exception {
-        UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
         assertTrue(userInfo != null);
 
         List<UserInfo> list = mUserManager.getUsers();
@@ -83,12 +92,11 @@
             }
         }
         assertTrue(found);
-        removeUser(userInfo.id);
     }
 
     public void testAdd2Users() throws Exception {
-        UserInfo user1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
-        UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_ADMIN);
+        UserInfo user1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo user2 = createUser("User 2", UserInfo.FLAG_ADMIN);
 
         assertTrue(user1 != null);
         assertTrue(user2 != null);
@@ -96,41 +104,65 @@
         assertTrue(findUser(0));
         assertTrue(findUser(user1.id));
         assertTrue(findUser(user2.id));
-        removeUser(user1.id);
-        removeUser(user2.id);
     }
 
     public void testRemoveUser() throws Exception {
-        UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo userInfo = createUser("Guest 1", UserInfo.FLAG_GUEST);
         removeUser(userInfo.id);
 
         assertFalse(findUser(userInfo.id));
     }
 
     public void testAddGuest() throws Exception {
-        UserInfo userInfo1 = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
-        UserInfo userInfo2 = mUserManager.createUser("Guest 2", UserInfo.FLAG_GUEST);
+        UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
+        UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST);
         assertNotNull(userInfo1);
         assertNull(userInfo2);
-
-        // Cleanup
-        removeUser(userInfo1.id);
     }
 
     // Make sure only one managed profile can be created
     public void testAddManagedProfile() throws Exception {
-        UserInfo userInfo1 = mUserManager.createProfileForUser("Managed 1",
+        UserInfo userInfo1 = createProfileForUser("Managed 1",
                 UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
-        UserInfo userInfo2 = mUserManager.createProfileForUser("Managed 2",
+        UserInfo userInfo2 = createProfileForUser("Managed 2",
                 UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
         assertNotNull(userInfo1);
         assertNull(userInfo2);
         // Verify that current user is not a managed profile
         assertFalse(mUserManager.isManagedProfile());
-        // Cleanup
-        removeUser(userInfo1.id);
     }
 
+    public void testGetUserCreationTime() throws Exception {
+        UserInfo profile = createProfileForUser("Managed 1",
+                UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+        assertNotNull(profile);
+        assertTrue("creationTime must be set when the profile is created",
+                profile.creationTime > 0);
+        assertEquals(profile.creationTime, mUserManager.getUserCreationTime(profile.id));
+
+        long ownerCreationTime = mUserManager.getUserInfo(UserHandle.USER_OWNER).creationTime;
+        assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(UserHandle.USER_OWNER));
+
+        try {
+            int noSuchUserId = 100500;
+            mUserManager.getUserCreationTime(noSuchUserId);
+            fail("SecurityException should be thrown for nonexistent user");
+        } catch (Exception e) {
+            assertTrue("SecurityException should be thrown for nonexistent user, but was: " + e,
+                    e instanceof SecurityException);
+        }
+
+        UserInfo user = createUser("User 1", 0);
+        try {
+            mUserManager.getUserCreationTime(user.id);
+            fail("SecurityException should be thrown for other user");
+        } catch (Exception e) {
+            assertTrue("SecurityException should be thrown for other user, but was: " + e,
+                    e instanceof SecurityException);
+        }
+    }
+
+
     private boolean findUser(int id) {
         List<UserInfo> list = mUserManager.getUsers();
 
@@ -143,40 +175,29 @@
     }
 
     public void testSerialNumber() {
-        UserInfo user1 = mUserManager.createUser("User 1", UserInfo.FLAG_RESTRICTED);
+        UserInfo user1 = createUser("User 1", UserInfo.FLAG_RESTRICTED);
         int serialNumber1 = user1.serialNumber;
         assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
         assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
-        removeUser(user1.id);
-        UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED);
+        UserInfo user2 = createUser("User 2", UserInfo.FLAG_RESTRICTED);
         int serialNumber2 = user2.serialNumber;
         assertFalse(serialNumber1 == serialNumber2);
         assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
         assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
-        removeUser(user2.id);
     }
 
     public void testMaxUsers() {
         int N = UserManager.getMaxSupportedUsers();
         int count = mUserManager.getUsers().size();
-        List<UserInfo> created = new ArrayList<UserInfo>();
         // Create as many users as permitted and make sure creation passes
         while (count < N) {
-            UserInfo ui = mUserManager.createUser("User " + count, 0);
+            UserInfo ui = createUser("User " + count, 0);
             assertNotNull(ui);
-            created.add(ui);
             count++;
         }
         // Try to create one more user and make sure it fails
-        UserInfo extra = null;
-        assertNull(extra = mUserManager.createUser("One more", 0));
-        if (extra != null) {
-            removeUser(extra.id);
-        }
-        while (!created.isEmpty()) {
-            UserInfo user = created.remove(0);
-            removeUser(user.id);
-        }
+        UserInfo extra = createUser("One more", 0);
+        assertNull(extra);
     }
 
     public void testRestrictions() {
@@ -198,11 +219,27 @@
             mUserManager.removeUser(userId);
             while (mUserManager.getUserInfo(userId) != null) {
                 try {
-                    mUserLock.wait(1000);
+                    mUserLock.wait(500);
                 } catch (InterruptedException ie) {
                 }
             }
         }
     }
 
+    private UserInfo createUser(String name, int flags) {
+        UserInfo user = mUserManager.createUser(name, flags);
+        if (user != null) {
+            usersToRemove.add(user.id);
+        }
+        return user;
+    }
+
+    private UserInfo createProfileForUser(String name, int flags, int userHandle) {
+        UserInfo profile = mUserManager.createProfileForUser(name, flags, userHandle);
+        if (profile != null) {
+            usersToRemove.add(profile.id);
+        }
+        return profile;
+    }
+
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 235567c..4498b84 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -18,6 +18,7 @@
 
 import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageStatsManager;
+import android.os.Build;
 import android.util.AtomicFile;
 import android.util.Slog;
 
@@ -35,7 +36,7 @@
  * Provides an interface to query for UsageStat data from an XML database.
  */
 class UsageStatsDatabase {
-    private static final int CURRENT_VERSION = 2;
+    private static final int CURRENT_VERSION = 3;
 
     private static final String TAG = "UsageStatsDatabase";
     private static final boolean DEBUG = UsageStatsService.DEBUG;
@@ -47,6 +48,8 @@
     private final TimeSparseArray<AtomicFile>[] mSortedStatFiles;
     private final UnixCalendar mCal;
     private final File mVersionFile;
+    private boolean mFirstUpdate;
+    private boolean mNewUpdate;
 
     public UsageStatsDatabase(File dir) {
         mIntervalDirs = new File[] {
@@ -73,7 +76,7 @@
                 }
             }
 
-            checkVersionLocked();
+            checkVersionAndBuildLocked();
             indexFilesLocked();
 
             // Delete files that are in the future.
@@ -194,10 +197,35 @@
         }
     }
 
-    private void checkVersionLocked() {
+    /**
+     * Is this the first update to the system from L to M?
+     */
+    boolean isFirstUpdate() {
+        return mFirstUpdate;
+    }
+
+    /**
+     * Is this a system update since we started tracking build fingerprint in the version file?
+     */
+    boolean isNewUpdate() {
+        return mNewUpdate;
+    }
+
+    private void checkVersionAndBuildLocked() {
         int version;
+        String buildFingerprint;
+        String currentFingerprint = getBuildFingerprint();
+        mFirstUpdate = true;
+        mNewUpdate = true;
         try (BufferedReader reader = new BufferedReader(new FileReader(mVersionFile))) {
             version = Integer.parseInt(reader.readLine());
+            buildFingerprint = reader.readLine();
+            if (buildFingerprint != null) {
+                mFirstUpdate = false;
+            }
+            if (currentFingerprint.equals(buildFingerprint)) {
+                mNewUpdate = false;
+            }
         } catch (NumberFormatException | IOException e) {
             version = 0;
         }
@@ -205,9 +233,15 @@
         if (version != CURRENT_VERSION) {
             Slog.i(TAG, "Upgrading from version " + version + " to " + CURRENT_VERSION);
             doUpgradeLocked(version);
+        }
 
+        if (version != CURRENT_VERSION || mNewUpdate) {
             try (BufferedWriter writer = new BufferedWriter(new FileWriter(mVersionFile))) {
                 writer.write(Integer.toString(CURRENT_VERSION));
+                writer.write("\n");
+                writer.write(currentFingerprint);
+                writer.write("\n");
+                writer.flush();
             } catch (IOException e) {
                 Slog.e(TAG, "Failed to write new version");
                 throw new RuntimeException(e);
@@ -215,6 +249,12 @@
         }
     }
 
+    private String getBuildFingerprint() {
+        return Build.VERSION.RELEASE + ";"
+                + Build.VERSION.CODENAME + ";"
+                + Build.VERSION.INCREMENTAL;
+    }
+
     private void doUpgradeLocked(int thisVersion) {
         if (thisVersion < 2) {
             // Delete all files if we are version 0. This is a pre-release version,
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 5eefe6a..cc0ab81 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -21,8 +21,10 @@
 import android.app.usage.ConfigurationStats;
 import android.app.usage.IUsageStatsManager;
 import android.app.usage.UsageEvents;
+import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManagerInternal;
+import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -32,6 +34,8 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
+import android.database.ContentObserver;
+import android.net.Uri;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
@@ -42,6 +46,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -53,6 +58,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
@@ -74,6 +80,7 @@
     static final int MSG_REPORT_EVENT = 0;
     static final int MSG_FLUSH_TO_DISK = 1;
     static final int MSG_REMOVE_USER = 2;
+    static final int MSG_INFORM_LISTENERS = 3;
 
     private final Object mLock = new Object();
     Handler mHandler;
@@ -85,6 +92,12 @@
     long mRealTimeSnapshot;
     long mSystemTimeSnapshot;
 
+    private static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 1L * 24 * 60 * 60 * 1000; // 1 day
+    private long mAppIdleDurationMillis;
+
+    private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
+            mPackageAccessListeners = new ArrayList<>();
+
     public UsageStatsService(Context context) {
         super(context);
     }
@@ -112,11 +125,24 @@
 
         mRealTimeSnapshot = SystemClock.elapsedRealtime();
         mSystemTimeSnapshot = System.currentTimeMillis();
+        // Look at primary user's secure setting for this. TODO: Maybe apply different
+        // thresholds for different users.
+        mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
+                Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
+                UserHandle.USER_OWNER);
 
         publishLocalService(UsageStatsManagerInternal.class, new LocalService());
         publishBinderService(Context.USAGE_STATS_SERVICE, new BinderService());
     }
 
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            // Observe changes to the threshold
+            new SettingsObserver(mHandler).registerObserver();
+        }
+    }
+
     private class UserRemovedReceiver extends BroadcastReceiver {
 
         @Override
@@ -235,7 +261,19 @@
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+            final long lastUsed = service.getLastPackageAccessTime(event.mPackage);
+            final boolean previouslyIdle = hasPassedIdleDuration(lastUsed);
             service.reportEvent(event);
+            // Inform listeners if necessary
+            if ((event.mEventType == Event.MOVE_TO_FOREGROUND
+                    || event.mEventType == Event.MOVE_TO_BACKGROUND
+                    || event.mEventType == Event.INTERACTION)) {
+                if (previouslyIdle) {
+                    // Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
+                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
+                            /* idle = */ 0, event.mPackage));
+                }
+            }
         }
     }
 
@@ -308,6 +346,53 @@
         }
     }
 
+    /**
+     * Called by LocalService stub.
+     */
+    long getLastPackageAccessTime(String packageName, int userId) {
+        synchronized (mLock) {
+            final long timeNow = checkAndGetTimeLocked();
+            // android package is always considered non-idle.
+            // TODO: Add a generic whitelisting mechanism
+            if (packageName.equals("android")) {
+                return timeNow;
+            }
+            final UserUsageStatsService service =
+                    getUserDataAndInitializeIfNeededLocked(userId, timeNow);
+            return service.getLastPackageAccessTime(packageName);
+        }
+    }
+
+    void addListener(AppIdleStateChangeListener listener) {
+        synchronized (mLock) {
+            if (!mPackageAccessListeners.contains(listener)) {
+                mPackageAccessListeners.add(listener);
+            }
+        }
+    }
+
+    void removeListener(AppIdleStateChangeListener listener) {
+        synchronized (mLock) {
+            mPackageAccessListeners.remove(listener);
+        }
+    }
+
+    private boolean hasPassedIdleDuration(long lastUsed) {
+        final long now = System.currentTimeMillis();
+        return lastUsed < now - mAppIdleDurationMillis;
+    }
+
+    boolean isAppIdle(String packageName, int userId) {
+        final long lastUsed = getLastPackageAccessTime(packageName, userId);
+        return hasPassedIdleDuration(lastUsed);
+    }
+
+    void informListeners(String packageName, int userId, boolean isIdle) {
+        for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
+            listener.onAppIdleStateChanged(packageName, userId, isIdle);
+        }
+    }
+
     private static boolean validRange(long currentTime, long beginTime, long endTime) {
         return beginTime <= currentTime && beginTime < endTime;
     }
@@ -366,6 +451,10 @@
                     removeUser(msg.arg1);
                     break;
 
+                case MSG_INFORM_LISTENERS:
+                    informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
+                    break;
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -373,6 +462,29 @@
         }
     }
 
+    /**
+     * Observe settings changes for Settings.Secure.APP_IDLE_DURATION.
+     */
+    private class SettingsObserver extends ContentObserver {
+
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        void registerObserver() {
+            getContext().getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.APP_IDLE_DURATION), false, this, UserHandle.USER_OWNER);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri, int userId) {
+            mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
+                    Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
+                    UserHandle.USER_OWNER);
+            // TODO: Check if we need to update idle states of all the apps
+        }
+    }
+
     private class BinderService extends IUsageStatsManager.Stub {
 
         private boolean hasPermission(String callingPackage) {
@@ -523,11 +635,32 @@
         }
 
         @Override
+        public boolean isAppIdle(String packageName, int userId) {
+            return UsageStatsService.this.isAppIdle(packageName, userId);
+        }
+
+        @Override
+        public long getLastPackageAccessTime(String packageName, int userId) {
+            return UsageStatsService.this.getLastPackageAccessTime(packageName, userId);
+        }
+
+        @Override
         public void prepareShutdown() {
             // This method *WILL* do IO work, but we must block until it is finished or else
             // we might not shutdown cleanly. This is ok to do with the 'am' lock held, because
             // we are shutting down.
             shutdown();
         }
+
+        @Override
+        public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
+            UsageStatsService.this.addListener(listener);
+        }
+
+        @Override
+        public void removeAppIdleStateChangeListener(
+                AppIdleStateChangeListener listener) {
+            UsageStatsService.this.removeListener(listener);
+        }
     }
 }
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 75fa030..0a9481a 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -19,8 +19,11 @@
 import android.app.usage.ConfigurationStats;
 import android.app.usage.TimeSparseArray;
 import android.app.usage.UsageEvents;
+import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.os.SystemClock;
 import android.content.Context;
@@ -60,18 +63,21 @@
     private final UnixCalendar mDailyExpiryDate;
     private final StatsUpdatedListener mListener;
     private final String mLogPrefix;
+    private final int mUserId;
 
     interface StatsUpdatedListener {
         void onStatsUpdated();
     }
 
-    UserUsageStatsService(Context context, int userId, File usageStatsDir, StatsUpdatedListener listener) {
+    UserUsageStatsService(Context context, int userId, File usageStatsDir,
+            StatsUpdatedListener listener) {
         mContext = context;
         mDailyExpiryDate = new UnixCalendar(0);
         mDatabase = new UsageStatsDatabase(usageStatsDir);
         mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT];
         mListener = listener;
         mLogPrefix = "User[" + Integer.toString(userId) + "] ";
+        mUserId = userId;
     }
 
     void init(final long currentTimeMillis) {
@@ -127,6 +133,35 @@
 
             stat.updateConfigurationStats(null, stat.lastTimeSaved);
         }
+
+        if (mDatabase.isNewUpdate()) {
+            initializeDefaultsForApps(currentTimeMillis, mDatabase.isFirstUpdate());
+        }
+    }
+
+    /**
+     * If any of the apps don't have a last-used entry, add one now.
+     * @param currentTimeMillis the current time
+     * @param firstUpdate if it is the first update, touch all installed apps, otherwise only
+     *        touch the system apps
+     */
+    private void initializeDefaultsForApps(long currentTimeMillis, boolean firstUpdate) {
+        PackageManager pm = mContext.getPackageManager();
+        List<PackageInfo> packages = pm.getInstalledPackages(0, mUserId);
+        final int packageCount = packages.size();
+        for (int i = 0; i < packageCount; i++) {
+            final PackageInfo pi = packages.get(i);
+            String packageName = pi.packageName;
+            if (pi.applicationInfo != null && (firstUpdate || pi.applicationInfo.isSystemApp())
+                    && getLastPackageAccessTime(packageName) == -1) {
+                for (IntervalStats stats : mCurrentStats) {
+                    stats.update(packageName, currentTimeMillis, Event.INTERACTION);
+                    mStatsChanged = true;
+                }
+            }
+        }
+        // Persist the new OTA-related access stats.
+        persistActiveStats();
     }
 
     void onTimeChanged(long oldTime, long newTime) {
@@ -161,7 +196,9 @@
         if (currentDailyStats.events == null) {
             currentDailyStats.events = new TimeSparseArray<>();
         }
-        currentDailyStats.events.put(event.mTimeStamp, event);
+        if (event.mEventType != UsageEvents.Event.INTERACTION) {
+            currentDailyStats.events.put(event.mTimeStamp, event);
+        }
 
         for (IntervalStats stats : mCurrentStats) {
             if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
@@ -328,6 +365,16 @@
         return new UsageEvents(results, table);
     }
 
+    long getLastPackageAccessTime(String packageName) {
+        final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
+        UsageStats packageUsage;
+        if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
+            return -1;
+        } else {
+            return packageUsage.getLastTimeUsed();
+        }
+    }
+
     void persistActiveStats() {
         if (mStatsChanged) {
             Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk");
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 2728af1..8f0c6c8 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -469,10 +469,12 @@
         if (enabled && mPeripheralMidiDevice == null) {
             Bundle properties = new Bundle();
             Resources r = mContext.getResources();
+            properties.putString(MidiDeviceInfo.PROPERTY_NAME, r.getString(
+                    com.android.internal.R.string.usb_midi_peripheral_name));
             properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
                     com.android.internal.R.string.usb_midi_peripheral_manufacturer_name));
             properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, r.getString(
-                    com.android.internal.R.string.usb_midi_peripheral_model_name));
+                    com.android.internal.R.string.usb_midi_peripheral_product_name));
             properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
             properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
             mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 6ece888..671cf01 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -45,7 +45,8 @@
 
     private MidiDeviceServer mServer;
 
-    private final MidiEventScheduler mEventScheduler;
+    // event schedulers for each output port
+    private final MidiEventScheduler[] mEventSchedulers;
 
     private static final int BUFFER_SIZE = 512;
 
@@ -99,10 +100,11 @@
         }
 
         mOutputStreams = new FileOutputStream[outputCount];
+        mEventSchedulers = new MidiEventScheduler[outputCount];
         for (int i = 0; i < outputCount; i++) {
             mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
+            mEventSchedulers[i] = new MidiEventScheduler();
         }
-        mEventScheduler = new MidiEventScheduler(inputCount);
     }
 
     private boolean register(Context context, Bundle properties) {
@@ -116,7 +118,7 @@
         int outputCount = mOutputStreams.length;
         MidiReceiver[] inputPortReceivers = new MidiReceiver[inputCount];
         for (int port = 0; port < inputCount; port++) {
-            inputPortReceivers[port] = mEventScheduler.getReceiver(port);
+            inputPortReceivers[port] = mEventSchedulers[port].getReceiver();
         }
 
         mServer = midiManager.createDeviceServer(inputPortReceivers, outputCount,
@@ -126,7 +128,7 @@
         }
         final MidiReceiver[] outputReceivers = mServer.getOutputPortReceivers();
 
-        // Create input thread
+        // Create input thread which will read from all input ports
         new Thread("UsbMidiDevice input thread") {
             @Override
             public void run() {
@@ -161,38 +163,46 @@
             }
         }.start();
 
-        // Create output thread
-        new Thread("UsbMidiDevice output thread") {
-            @Override
-            public void run() {
-                while (true) {
-                    MidiEvent event;
-                    try {
-                        event = (MidiEvent)mEventScheduler.waitNextEvent();
-                    } catch (InterruptedException e) {
-                        // try again
-                        continue;
+        // Create output thread for each output port
+        for (int port = 0; port < outputCount; port++) {
+            final MidiEventScheduler eventSchedulerF = mEventSchedulers[port];
+            final FileOutputStream outputStreamF = mOutputStreams[port];
+            final int portF = port;
+
+            new Thread("UsbMidiDevice output thread " + port) {
+                @Override
+                public void run() {
+                    while (true) {
+                        MidiEvent event;
+                        try {
+                            event = (MidiEvent)eventSchedulerF.waitNextEvent();
+                        } catch (InterruptedException e) {
+                            // try again
+                            continue;
+                        }
+                        if (event == null) {
+                            break;
+                        }
+                        try {
+                            outputStreamF.write(event.data, 0, event.count);
+                        } catch (IOException e) {
+                            Log.e(TAG, "write failed for port " + portF);
+                        }
+                        eventSchedulerF.addEventToPool(event);
                     }
-                    if (event == null) {
-                        break;
-                    }
-                    try {
-                        mOutputStreams[event.portNumber].write(event.data, 0, event.count);
-                    } catch (IOException e) {
-                        Log.e(TAG, "write failed for port " + event.portNumber);
-                    }
-                    mEventScheduler.addEventToPool(event);
+                    Log.d(TAG, "output thread exit");
                 }
-                Log.d(TAG, "output thread exit");
-            }
-        }.start();
+            }.start();
+        }
 
         return true;
     }
 
     @Override
     public void close() throws IOException {
-        mEventScheduler.close();
+        for (int i = 0; i < mEventSchedulers.length; i++) {
+            mEventSchedulers[i].close();
+        }
 
         if (mServer != null) {
             mServer.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index f032ccf..8a28d51 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -50,6 +50,7 @@
 import android.util.Slog;
 
 import com.android.internal.app.IVoiceInteractionManagerService;
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
@@ -396,7 +397,8 @@
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    mImpl.showSessionLocked(callingPid, callingUid, args, flags);
+                    mImpl.showSessionLocked(callingPid, callingUid, args, flags,
+                            null /* showCallback */);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -434,7 +436,8 @@
                 final int callingUid = Binder.getCallingUid();
                 final long caller = Binder.clearCallingIdentity();
                 try {
-                    return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags);
+                    return mImpl.showSessionLocked(callingPid, callingUid, sessionArgs, flags,
+                            null /* showCallback */);
                 } finally {
                     Binder.restoreCallingIdentity(caller);
                 }
@@ -518,13 +521,7 @@
 
         @Override
         public KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
-            synchronized (this) {
-                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Caller does not hold the permission "
-                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
-                }
-            }
+            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
 
             if (bcp47Locale == null) {
                 throw new IllegalArgumentException("Illegal argument(s) in getKeyphraseSoundModel");
@@ -541,15 +538,9 @@
 
         @Override
         public int updateKeyphraseSoundModel(KeyphraseSoundModel model) {
-            synchronized (this) {
-                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Caller does not hold the permission "
-                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
-                }
-                if (model == null) {
-                    throw new IllegalArgumentException("Model must not be null");
-                }
+            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
+            if (model == null) {
+                throw new IllegalArgumentException("Model must not be null");
             }
 
             final long caller = Binder.clearCallingIdentity();
@@ -572,13 +563,7 @@
 
         @Override
         public int deleteKeyphraseSoundModel(int keyphraseId, String bcp47Locale) {
-            synchronized (this) {
-                if (mContext.checkCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES)
-                        != PackageManager.PERMISSION_GRANTED) {
-                    throw new SecurityException("Caller does not hold the permission "
-                            + Manifest.permission.MANAGE_VOICE_KEYPHRASES);
-                }
-            }
+            enforceCallingPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES);
 
             if (bcp47Locale == null) {
                 throw new IllegalArgumentException(
@@ -707,6 +692,54 @@
         }
 
         @Override
+        public ComponentName getActiveServiceComponentName() {
+            enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+            synchronized (this) {
+                return mImpl != null ? mImpl.mComponent : null;
+            }
+        }
+
+        @Override
+        public void showSessionForActiveService(IVoiceInteractionSessionShowCallback showCallback) {
+            enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+            synchronized (this) {
+                if (mImpl == null) {
+                    Slog.w(TAG, "showSessionForActiveService without running voice interaction"
+                            + "service");
+                    return;
+                }
+                final int callingPid = Binder.getCallingPid();
+                final int callingUid = Binder.getCallingUid();
+                final long caller = Binder.clearCallingIdentity();
+                try {
+                    mImpl.showSessionLocked(callingPid, callingUid, new Bundle() /* sessionArgs */,
+                            VoiceInteractionService.START_SOURCE_ASSIST_GESTURE
+                                    | VoiceInteractionService.START_WITH_ASSIST
+                                    | VoiceInteractionService.START_WITH_SCREENSHOT,
+                            showCallback);
+                } finally {
+                    Binder.restoreCallingIdentity(caller);
+                }
+            }
+        }
+
+        @Override
+        public boolean isSessionRunning() {
+            enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+            synchronized (this) {
+                return mImpl != null && mImpl.mActiveSession != null;
+            }
+        }
+
+        @Override
+        public boolean activeServiceSupportsAssistGesture() {
+            enforceCallingPermission(Manifest.permission.ACCESS_VOICE_INTERACTION_SERVICE);
+            synchronized (this) {
+                return mImpl != null && mImpl.mInfo.getSupportsAssistGesture();
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
@@ -726,6 +759,12 @@
             mSoundTriggerHelper.dump(fd, pw, args);
         }
 
+        private void enforceCallingPermission(String permission) {
+            if (mContext.checkCallingPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Caller does not hold the permission " + permission);
+            }
+        }
+
         class SettingsObserver extends ContentObserver {
             SettingsObserver(Handler handler) {
                 super(handler);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 5a91b88..bca757b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -39,6 +39,7 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 
 import java.io.FileDescriptor;
@@ -134,16 +135,20 @@
         mContext.registerReceiver(mBroadcastReceiver, filter, null, handler);
     }
 
-    public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags) {
+    public boolean showSessionLocked(int callingPid, int callingUid, Bundle args, int flags,
+            IVoiceInteractionSessionShowCallback showCallback) {
         if (mActiveSession == null) {
             mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
                     mUser, mContext, this, callingPid, callingUid);
         }
-        return mActiveSession.showLocked(args, flags);
+        return mActiveSession.showLocked(args, flags, showCallback);
     }
 
     public boolean hideSessionLocked(int callingPid, int callingUid) {
-        return mActiveSession.hideLocked();
+        if (mActiveSession != null) {
+            return mActiveSession.hideLocked();
+        }
+        return false;
     }
 
     public boolean deliverNewSessionLocked(int callingPid, int callingUid, IBinder token,
@@ -163,6 +168,10 @@
                 Slog.w(TAG, "startVoiceActivity does not match active session");
                 return ActivityManager.START_CANCELED;
             }
+            if (!mActiveSession.mShown) {
+                Slog.w(TAG, "startVoiceActivity not allowed on hidden session");
+                return ActivityManager.START_CANCELED;
+            }
             intent = new Intent(intent);
             intent.addCategory(Intent.CATEGORY_VOICE);
             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 7a379c2..fb83956 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.AppOpsManager;
 import android.app.AssistContent;
 import android.app.IActivityManager;
 import android.content.ClipData;
@@ -41,10 +42,12 @@
 import android.view.IWindowManager;
 import android.view.WindowManager;
 import com.android.internal.app.IAssistScreenshotReceiver;
+import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
 final class VoiceInteractionSessionConnection implements ServiceConnection {
     final static String TAG = "VoiceInteractionServiceManager";
@@ -60,6 +63,7 @@
     final int mCallingUid;
     final IActivityManager mAm;
     final IWindowManager mIWindowManager;
+    final AppOpsManager mAppOps;
     final IBinder mPermissionOwner;
     boolean mShown;
     Bundle mShowArgs;
@@ -74,6 +78,26 @@
     Bundle mAssistData;
     boolean mHaveScreenshot;
     Bitmap mScreenshot;
+    ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
+
+    IVoiceInteractionSessionShowCallback mShowCallback =
+            new IVoiceInteractionSessionShowCallback.Stub() {
+        @Override
+        public void onFailed() throws RemoteException {
+            synchronized (mLock) {
+                notifyPendingShowCallbacksFailedLocked();
+            }
+        }
+
+        @Override
+        public void onShown() throws RemoteException {
+            synchronized (mLock) {
+                // TODO: Figure out whether this is good enough or whether we need to hook into
+                // Window manager to actually wait for the window to be drawn.
+                notifyPendingShowCallbacksShownLocked();
+            }
+        }
+    };
 
     public interface Callback {
         public void sessionConnectionGone(VoiceInteractionSessionConnection connection);
@@ -126,6 +150,7 @@
         mAm = ActivityManagerNative.getDefault();
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
+        mAppOps = context.getSystemService(AppOpsManager.class);
         IBinder permOwner = null;
         try {
             permOwner = mAm.newUriPermissionOwner("voicesession:"
@@ -137,7 +162,8 @@
         mBindIntent = new Intent(VoiceInteractionService.SERVICE_INTERFACE);
         mBindIntent.setComponent(mSessionComponentName);
         mBound = mContext.bindServiceAsUser(mBindIntent, this,
-                Context.BIND_AUTO_CREATE|Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
+                Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY
+                        | Context.BIND_ALLOW_OOM_MANAGEMENT, new UserHandle(mUser));
         if (mBound) {
             try {
                 mIWindowManager.addWindowToken(mToken,
@@ -151,7 +177,8 @@
         }
     }
 
-    public boolean showLocked(Bundle args, int flags) {
+    public boolean showLocked(Bundle args, int flags,
+            IVoiceInteractionSessionShowCallback showCallback) {
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -163,34 +190,54 @@
             mShowFlags = flags;
             mHaveAssistData = false;
             if ((flags&VoiceInteractionService.START_WITH_ASSIST) != 0) {
-                try {
-                    mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
-                            mAssistReceiver);
-                } catch (RemoteException e) {
+                if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
+                        mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) {
+                    try {
+                        mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+                                mAssistReceiver);
+                    } catch (RemoteException e) {
+                    }
+                } else {
+                    mHaveAssistData = true;
+                    mAssistData = null;
                 }
             } else {
                 mAssistData = null;
             }
             mHaveScreenshot = false;
             if ((flags&VoiceInteractionService.START_WITH_SCREENSHOT) != 0) {
-                try {
-                    mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
-                } catch (RemoteException e) {
+                if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid,
+                        mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) {
+                    try {
+                        mIWindowManager.requestAssistScreenshot(mScreenshotReceiver);
+                    } catch (RemoteException e) {
+                    }
+                } else {
+                    mHaveScreenshot = true;
+                    mScreenshot = null;
                 }
             } else {
                 mScreenshot = null;
             }
             if (mSession != null) {
                 try {
-                    mSession.show(mShowArgs, mShowFlags);
+                    mSession.show(mShowArgs, mShowFlags, showCallback);
                     mShowArgs = null;
                     mShowFlags = 0;
                 } catch (RemoteException e) {
                 }
                 deliverSessionDataLocked();
+            } else if (showCallback != null) {
+                mPendingShowCallbacks.add(showCallback);
             }
             return true;
         }
+        if (showCallback != null) {
+            try {
+                showCallback.onFailed();
+            } catch (RemoteException e) {
+            }
+        }
         return false;
     }
 
@@ -304,6 +351,12 @@
                             mUser);
                 } catch (RemoteException e) {
                 }
+                if (mSession != null) {
+                    try {
+                        mAm.finishVoiceTask(mSession);
+                    } catch (RemoteException e) {
+                    }
+                }
             }
             if (mFullyBound) {
                 mContext.unbindService(mFullConnection);
@@ -320,7 +373,7 @@
         mInteractor = interactor;
         if (mShown) {
             try {
-                session.show(mShowArgs, mShowFlags);
+                session.show(mShowArgs, mShowFlags, mShowCallback);
                 mShowArgs = null;
                 mShowFlags = 0;
             } catch (RemoteException e) {
@@ -330,6 +383,26 @@
         return true;
     }
 
+    private void notifyPendingShowCallbacksShownLocked() {
+        for (int i = 0; i < mPendingShowCallbacks.size(); i++) {
+            try {
+                mPendingShowCallbacks.get(i).onShown();
+            } catch (RemoteException e) {
+            }
+        }
+        mPendingShowCallbacks.clear();
+    }
+
+    private void notifyPendingShowCallbacksFailedLocked() {
+        for (int i = 0; i < mPendingShowCallbacks.size(); i++) {
+            try {
+                mPendingShowCallbacks.get(i).onFailed();
+            } catch (RemoteException e) {
+            }
+        }
+        mPendingShowCallbacks.clear();
+    }
+
     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         synchronized (mLock) {
diff --git a/telecomm/java/android/telecom/AuthenticatorService.java b/telecomm/java/android/telecom/AuthenticatorService.java
index 39717c3..7aa105d 100644
--- a/telecomm/java/android/telecom/AuthenticatorService.java
+++ b/telecomm/java/android/telecom/AuthenticatorService.java
@@ -19,6 +19,7 @@
 import android.accounts.Account;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.NetworkErrorException;
+import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -28,7 +29,10 @@
 /**
  * A generic stub account authenticator service often used for sync adapters that do not directly
  * involve accounts.
+ *
+ * @hide
  */
+@SystemApi
 public class AuthenticatorService extends Service {
     private static Authenticator mAuthenticator;
 
diff --git a/telecomm/java/android/telecom/Voicemail.java b/telecomm/java/android/telecom/Voicemail.java
index a884c5f..186c199 100644
--- a/telecomm/java/android/telecom/Voicemail.java
+++ b/telecomm/java/android/telecom/Voicemail.java
@@ -16,13 +16,17 @@
 
 package android.telecom;
 
+import android.annotation.SystemApi;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 /**
  * Represents a single voicemail stored in the voicemail content provider.
+ *
+ * @hide
  */
+@SystemApi
 public class Voicemail implements Parcelable {
     private final Long mTimestamp;
     private final String mNumber;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6bc6de63..c5573ba 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -575,6 +575,37 @@
      */
     public static final String EXTRA_DATA_FAILURE_CAUSE = PhoneConstants.DATA_FAILURE_CAUSE_KEY;
 
+    /**
+     * Response codes for sim activation. Activation completed successfully.
+     * @hide
+     */
+    @SystemApi
+    public static final int SIM_ACTIVATION_RESULT_COMPLETE = 0;
+    /**
+     * Response codes for sim activation. Activation not supported (device has no SIM).
+     * @hide
+     */
+    @SystemApi
+    public static final int SIM_ACTIVATION_RESULT_NOT_SUPPORTED = 1;
+    /**
+     * Response codes for sim activation. Activation is in progress.
+     * @hide
+     */
+    @SystemApi
+    public static final int SIM_ACTIVATION_RESULT_IN_PROGRESS = 2;
+    /**
+     * Response codes for sim activation. Activation failed to complete.
+     * @hide
+     */
+    @SystemApi
+    public static final int SIM_ACTIVATION_RESULT_FAILED = 3;
+    /**
+     * Response codes for sim activation. Activation canceled by user.
+     * @hide
+     */
+    @SystemApi
+    public static final int SIM_ACTIVATION_RESULT_CANCELED = 4;
+
     //
     //
     // Device Info
@@ -3982,7 +4013,10 @@
      */
     public boolean canChangeDtmfToneLength() {
         try {
-            return getITelephony().canChangeDtmfToneLength();
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.canChangeDtmfToneLength();
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
         }
@@ -3996,7 +4030,10 @@
      */
     public boolean isWorldPhone() {
         try {
-            return getITelephony().isWorldPhone();
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.isWorldPhone();
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
         }
@@ -4010,7 +4047,10 @@
      */
     public boolean isTtyModeSupported() {
         try {
-            return getITelephony().isTtyModeSupported();
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.isTtyModeSupported();
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isTtyModeSupported", e);
         }
@@ -4025,7 +4065,10 @@
      */
     public boolean isHearingAidCompatibilitySupported() {
         try {
-            return getITelephony().isHearingAidCompatibilitySupported();
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.isHearingAidCompatibilitySupported();
+            }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelephony#isHearingAidCompatibilitySupported", e);
         }
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 8740e19..239c16a 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -270,7 +270,7 @@
         return "{ serviceType=" + mServiceType +
                 ", callType=" + mCallType +
                 ", restrictCause=" + mRestrictCause +
-                ", callExtras=" + mCallExtras.toString() +
+                //", callExtras=" + mCallExtras.toString() +
                 ", mediaProfile=" + mMediaProfile.toString() + " }";
     }
 
diff --git a/telephony/java/com/android/ims/internal/IImsUt.aidl b/telephony/java/com/android/ims/internal/IImsUt.aidl
index 50a0169..c531ea5 100644
--- a/telephony/java/com/android/ims/internal/IImsUt.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUt.aidl
@@ -79,12 +79,13 @@
     /**
      * Updates the configuration of the call forward.
      */
-    int updateCallForward(int action, int condition, String number, int timeSeconds);
+    int updateCallForward(int action, int condition, String number,
+            int serviceClass, int timeSeconds);
 
     /**
      * Updates the configuration of the call waiting.
      */
-    int updateCallWaiting(boolean enable);
+    int updateCallWaiting(boolean enable, int serviceClass);
 
     /**
      * Updates the configuration of the CLIR supplementary service.
diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl
index 70ac268..24bdb7a 100644
--- a/telephony/java/com/android/internal/telephony/ISms.aidl
+++ b/telephony/java/com/android/internal/telephony/ISms.aidl
@@ -157,6 +157,34 @@
             in PendingIntent deliveryIntent);
 
     /**
+     * Send a data SMS. Only for use internally.
+     *
+     * @param smsc the SMSC to send the message through, or NULL for the
+     *  default SMSC
+     * @param data the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is sucessfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK<code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applicaitons,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param subId the subId id.
+     */
+    void sendDataForSubscriberWithSelfPermissions(int subId, String callingPkg, in String destAddr,
+            in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent,
+            in PendingIntent deliveryIntent);
+
+    /**
      * Send an SMS.
      *
      * @param smsc the SMSC to send the message through, or NULL for the
@@ -211,6 +239,34 @@
             in PendingIntent deliveryIntent);
 
     /**
+     * Send an SMS. Internal use only.
+     *
+     * @param smsc the SMSC to send the message through, or NULL for the
+     *  default SMSC
+     * @param text the body of the message to send
+     * @param sentIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is sucessfully sent, or failed.
+     *  The result code will be <code>Activity.RESULT_OK<code> for success,
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
+     *  The per-application based SMS control checks sentIntent. If sentIntent
+     *  is NULL the caller will be checked against all unknown applications,
+     *  which cause smaller number of SMS to be sent in checking period.
+     * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
+     *  broadcast when the message is delivered to the recipient.  The
+     *  raw pdu of the status report is in the extended data ("pdu").
+     * @param subId the subId on which the SMS has to be sent.
+     */
+    void sendTextForSubscriberWithSelfPermissions(in int subId, String callingPkg,
+            in String destAddr, in String scAddr, in String text, in PendingIntent sentIntent,
+            in PendingIntent deliveryIntent);
+
+    /**
      * Inject an SMS PDU into the android platform.
      *
      * @param pdu is the byte array of pdu to be injected into android application framework
diff --git a/test-runner/src/android/test/mock/MockCursor.java b/test-runner/src/android/test/mock/MockCursor.java
index a37c6eb..28fa0f8 100644
--- a/test-runner/src/android/test/mock/MockCursor.java
+++ b/test-runner/src/android/test/mock/MockCursor.java
@@ -35,162 +35,209 @@
  * </P>
  */
 public class MockCursor implements Cursor {
+    @Override
     public int getColumnCount() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public int getColumnIndex(String columnName) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public int getColumnIndexOrThrow(String columnName) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public String getColumnName(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public String[] getColumnNames() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public int getCount() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean isNull(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public int getInt(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public long getLong(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public short getShort(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public float getFloat(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public double getDouble(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public byte[] getBlob(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public String getString(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
+    public void setExtras(Bundle extras) {
+        throw new UnsupportedOperationException("unimplemented mock method");
+    }
+
+    @Override
     public Bundle getExtras() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public int getPosition() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean isAfterLast() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean isBeforeFirst() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean isFirst() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean isLast() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean move(int offset) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean moveToFirst() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean moveToLast() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean moveToNext() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean moveToPrevious() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean moveToPosition(int position) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
+    @Deprecated
     public void deactivate() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void close() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean isClosed() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
+    @Deprecated
     public boolean requery() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void registerContentObserver(ContentObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void registerDataSetObserver(DataSetObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public Bundle respond(Bundle extras) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public boolean getWantsAllOnMoveCalls() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void setNotificationUri(ContentResolver cr, Uri uri) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public Uri getNotificationUri() {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void unregisterContentObserver(ContentObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public void unregisterDataSetObserver(DataSetObserver observer) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
 
+    @Override
     public int getType(int columnIndex) {
         throw new UnsupportedOperationException("unimplemented mock method");
     }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index a204376..e78750c 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -485,14 +485,19 @@
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * @hide - to match hiding in superclass
-     */
+    /** {@hide} */
     @Override
     public void movePackage(String packageName, IPackageMoveObserver observer, int flags) {
         throw new UnsupportedOperationException();
     }
 
+    /** {@hide} */
+    @Override
+    public void movePackageAndData(String packageName, String volumeUuid,
+            IPackageMoveObserver observer) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public String getInstallerPackageName(String packageName) {
         throw new UnsupportedOperationException();
@@ -754,6 +759,21 @@
         throw new UnsupportedOperationException();
     }
 
+    @Override
+    public List<IntentFilter> getAllIntentFilters(String packageName) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getDefaultBrowserPackageName(int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean setDefaultBrowserPackageName(String packageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     /**
      * @hide
      */
diff --git a/tests/Assistant/Android.mk b/tests/Assist/Android.mk
similarity index 71%
copy from tests/Assistant/Android.mk
copy to tests/Assist/Android.mk
index bf8cc29..f31c4dd 100644
--- a/tests/Assistant/Android.mk
+++ b/tests/Assist/Android.mk
@@ -1,11 +1,10 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_MODULE_TAGS := tests
+
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_PACKAGE_NAME := Assistant
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_CERTIFICATE := platform
+LOCAL_PACKAGE_NAME := Assist
 
 include $(BUILD_PACKAGE)
diff --git a/tests/Assist/AndroidManifest.xml b/tests/Assist/AndroidManifest.xml
new file mode 100644
index 0000000..4eceed9
--- /dev/null
+++ b/tests/Assist/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.test.assist">
+
+    <application>
+        <service android:name="AssistInteractionService"
+                android:label="Test Assist Interaction Service"
+                android:permission="android.permission.BIND_VOICE_INTERACTION"
+                android:process=":interactor">
+            <meta-data android:name="android.voice_interaction"
+                       android:resource="@xml/interaction_service" />
+            <intent-filter>
+                <action android:name="android.service.voice.VoiceInteractionService" />
+            </intent-filter>
+            <meta-data
+                android:name="com.android.systemui.action_assist_icon"
+                android:resource="@drawable/assistant" />
+        </service>
+        <service android:name="AssistInteractionSessionService"
+                android:permission="android.permission.BIND_VOICE_INTERACTION"
+                android:process=":session">
+        </service>
+    </application>
+</manifest>
diff --git a/tests/Assist/res/drawable/assistant.xml b/tests/Assist/res/drawable/assistant.xml
new file mode 100644
index 0000000..2a89dda
--- /dev/null
+++ b/tests/Assist/res/drawable/assistant.xml
@@ -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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="48.0dp"
+        android:height="48.0dp"
+        android:viewportWidth="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:pathData="M0 0h48v48H0z"
+        android:fillColor="#00000000"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M38.0,4.0L10.0,4.0C7.79,4.0 6.0,5.79 6.0,8.0l0.0,28.0c0.0,2.21 1.79,4.0 4.0,4.0l8.0,0.0l6.0,6.0 6.0,-6.0l8.0,0.0c2.21,0.0 4.0,-1.79 4.0,-4.0L36.0,8.0c0.0,-2.21 -1.79,-4.0 -4.0,-4.0zM27.75,25.75L24.0,34.0l-3.75,-8.25L12.0,22.0l8.25,-3.75L24.0,10.0l3.75,8.25L36.0,22.0l-8.25,3.75z"/>
+</vector>
diff --git a/tests/Assist/res/drawable/navbar_scrim.xml b/tests/Assist/res/drawable/navbar_scrim.xml
new file mode 100644
index 0000000..52ed76d
--- /dev/null
+++ b/tests/Assist/res/drawable/navbar_scrim.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+            android:type="linear"
+            android:angle="90"
+            android:startColor="#33000000"
+            android:endColor="#00000000" />
+</shape>
\ No newline at end of file
diff --git a/tests/Assist/res/drawable/round_rect.xml b/tests/Assist/res/drawable/round_rect.xml
new file mode 100644
index 0000000..55937a0
--- /dev/null
+++ b/tests/Assist/res/drawable/round_rect.xml
@@ -0,0 +1,26 @@
+<?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:color="#e0e0e0">
+    <item>
+        <shape>
+            <solid android:color="#ffffff" />
+            <corners android:radius="2dp" />
+        </shape>
+    </item>
+</ripple>
\ No newline at end of file
diff --git a/tests/Assist/res/layout/assist.xml b/tests/Assist/res/layout/assist.xml
new file mode 100644
index 0000000..8c4be2d
--- /dev/null
+++ b/tests/Assist/res/layout/assist.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:orientation="vertical">
+
+    <com.android.test.assist.ScrimView
+        android:id="@+id/scrim"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#60000000"/>
+
+    <View
+        android:id="@+id/background"
+        android:layout_width="match_parent"
+        android:layout_height="350dp"
+        android:layout_gravity="bottom"
+        android:background="#e0e0e0"/>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="350dp"
+        android:orientation="vertical"
+        android:layout_gravity="bottom">
+
+        <FrameLayout
+            android:id="@+id/card1"
+            android:layout_width="match_parent"
+            android:layout_height="150dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginTop="16dp"
+            android:elevation="3dp"
+            android:background="@drawable/round_rect">
+        </FrameLayout>
+
+        <View
+            android:id="@+id/card2"
+            android:layout_width="match_parent"
+            android:layout_height="200dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginEnd="8dp"
+            android:layout_marginTop="16dp"
+            android:elevation="3dp"
+            android:background="@drawable/round_rect"/>
+
+    </LinearLayout>
+
+    <com.android.test.assist.ScrimView
+        android:id="@+id/navbar_scrim"
+        android:layout_width="match_parent"
+        android:layout_height="150dp"
+        android:layout_gravity="bottom"
+        android:background="@drawable/navbar_scrim"/>
+</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/drawable/ratingbar_full_material.xml b/tests/Assist/res/values/strings.xml
similarity index 61%
rename from core/res/res/drawable/ratingbar_full_material.xml
rename to tests/Assist/res/values/strings.xml
index 122dd1d..5331457 100644
--- a/core/res/res/drawable/ratingbar_full_material.xml
+++ b/tests/Assist/res/values/strings.xml
@@ -14,11 +14,15 @@
      limitations under the License.
 -->
 
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@id/background"
-        android:drawable="@drawable/ratingbar_full_empty_material" />
-    <item android:id="@id/secondaryProgress"
-        android:drawable="@drawable/ratingbar_full_empty_material" />
-    <item android:id="@id/progress" 
-        android:drawable="@drawable/ratingbar_full_filled_material" />
-</layer-list>
+<resources>
+
+    <string name="start">Start</string>
+    <string name="confirm">Confirm</string>
+    <string name="abort">Abort</string>
+    <string name="complete">Complete</string>
+    <string name="abortVoice">Abort Voice</string>
+    <string name="completeVoice">Complete Voice</string>
+    <string name="pickVoice">Pick Voice</string>
+    <string name="cancelVoice">Cancel</string>
+
+</resources>
diff --git a/tests/Assist/res/xml/interaction_service.xml b/tests/Assist/res/xml/interaction_service.xml
new file mode 100644
index 0000000..2fd50aa
--- /dev/null
+++ b/tests/Assist/res/xml/interaction_service.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<voice-interaction-service xmlns:android="http://schemas.android.com/apk/res/android"
+    android:sessionService="com.android.test.assist.AssistInteractionSessionService"
+    android:recognitionService="com.android.test.assist.AssistRecognitionService"
+    android:supportsAssistGesture="true"/>
diff --git a/tests/Assist/res/xml/recognition_service.xml b/tests/Assist/res/xml/recognition_service.xml
new file mode 100644
index 0000000..5b52c3c
--- /dev/null
+++ b/tests/Assist/res/xml/recognition_service.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<recognition-service/>
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/tests/Assist/src/com/android/test/assist/AssistInteractionService.java
similarity index 74%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to tests/Assist/src/com/android/test/assist/AssistInteractionService.java
index c9fd989..e6a6713 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/tests/Assist/src/com/android/test/assist/AssistInteractionService.java
@@ -11,9 +11,13 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+package com.android.test.assist;
+
+import android.service.voice.VoiceInteractionService;
+
+public class AssistInteractionService extends VoiceInteractionService {
+
+}
diff --git a/tests/Assist/src/com/android/test/assist/AssistInteractionSession.java b/tests/Assist/src/com/android/test/assist/AssistInteractionSession.java
new file mode 100644
index 0000000..0b522c0
--- /dev/null
+++ b/tests/Assist/src/com/android/test/assist/AssistInteractionSession.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.test.assist;
+
+import android.animation.Animator;
+import android.animation.RevealAnimator;
+import android.animation.ValueAnimator;
+import android.app.VoiceInteractor;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.os.Handler;
+import android.service.voice.VoiceInteractionService;
+import android.service.voice.VoiceInteractionSession;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAnimationUtils;
+import android.view.ViewTreeObserver;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+/**
+ * Sample session to show test assist transition.
+ */
+public class AssistInteractionSession extends VoiceInteractionSession {
+
+    private View mScrim;
+    private View mBackground;
+    private View mNavbarScrim;
+    private View mCard1;
+    private View mCard2;
+
+    private float mDensity;
+
+    public AssistInteractionSession(Context context) {
+        super(context);
+    }
+
+    public AssistInteractionSession(Context context, Handler handler) {
+        super(context, handler);
+    }
+
+    @Override
+    public void onConfirm(Caller caller,
+            Request request, CharSequence prompt, Bundle extras) {
+
+    }
+
+    @Override
+    public void onPickOption(Caller caller,
+            Request request, CharSequence prompt,
+            VoiceInteractor.PickOptionRequest.Option[] options, Bundle extras) {
+
+    }
+
+    @Override
+    public void onCommand(Caller caller,
+            Request request, String command, Bundle extras) {
+
+    }
+
+    @Override
+    public void onCreate(Bundle args) {
+        super.onCreate(args);
+
+        // Simulate slowness of Assist app
+        try {
+            Thread.sleep(1000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void onCancel(Request request) {
+
+    }
+
+    @Override
+    public View onCreateContentView() {
+        View v = getLayoutInflater().inflate(R.layout.assist, null);
+        mScrim = v.findViewById(R.id.scrim);
+        mBackground = v.findViewById(R.id.background);
+        mDensity = mScrim.getResources().getDisplayMetrics().density;
+        mCard1 = v.findViewById(R.id.card1);
+        mCard2 = v.findViewById(R.id.card2);
+        mNavbarScrim = v.findViewById(R.id.navbar_scrim);
+        return v;
+    }
+
+    @Override
+    public void onShow(Bundle args, int showFlags) {
+        super.onShow(args, showFlags);
+        if ((showFlags & VoiceInteractionService.START_SOURCE_ASSIST_GESTURE) != 0) {
+            mBackground.getViewTreeObserver().addOnPreDrawListener(
+                    new ViewTreeObserver.OnPreDrawListener() {
+                        @Override
+                        public boolean onPreDraw() {
+                            mBackground.getViewTreeObserver().removeOnPreDrawListener(this);
+                            playAssistAnimation();
+                            return true;
+                        }
+                    });
+        }
+    }
+
+    private void playAssistAnimation() {
+        Interpolator linearOutSlowIn = AnimationUtils.loadInterpolator(mBackground.getContext(),
+                android.R.interpolator.linear_out_slow_in);
+        Interpolator fastOutSlowIn = AnimationUtils.loadInterpolator(mBackground.getContext(),
+                android.R.interpolator.fast_out_slow_in);
+        mScrim.setAlpha(0f);
+        mScrim.animate()
+                .alpha(1f)
+                .setStartDelay(100)
+                .setDuration(500);
+        mBackground.setTranslationY(50 * mDensity);
+        mBackground.animate()
+                .translationY(0)
+                .setDuration(300)
+                .setInterpolator(linearOutSlowIn);
+        int centerX = mBackground.getWidth()/2;
+        int centerY = (int) (mBackground.getHeight()/5*3.8f);
+        int radius = (int) Math.sqrt(centerX*centerX + centerY*centerY) + 1;
+        Animator animator = ViewAnimationUtils.createCircularReveal(mBackground, centerX, centerY,
+                0, radius);
+        animator.setDuration(300);
+        animator.setInterpolator(fastOutSlowIn);
+        animator.start();
+
+        ValueAnimator colorAnim = ValueAnimator.ofArgb(Color.WHITE, 0xffe0e0e0);
+        colorAnim.setDuration(300);
+        colorAnim.setInterpolator(fastOutSlowIn);
+        colorAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mBackground.setBackgroundColor((Integer) animation.getAnimatedValue());
+            }
+        });
+        colorAnim.start();
+
+
+        mCard1.setY(mBackground.getHeight());
+        mCard2.setTranslationY(mCard1.getTranslationY());
+        mCard1.animate()
+                .translationY(0)
+                .setDuration(500)
+                .setInterpolator(linearOutSlowIn)
+                .setStartDelay(100);
+        mCard2.animate()
+                .translationY(0)
+                .setInterpolator(linearOutSlowIn)
+                .setStartDelay(150)
+                .setDuration(500);
+
+        mNavbarScrim.setAlpha(0f);
+        mNavbarScrim.animate()
+                .alpha(1f)
+                .setDuration(500)
+                .setStartDelay(100);
+    }
+
+    @Override
+    public void onHide() {
+        super.onHide();
+    }
+}
diff --git a/tests/Assist/src/com/android/test/assist/AssistInteractionSessionService.java b/tests/Assist/src/com/android/test/assist/AssistInteractionSessionService.java
new file mode 100644
index 0000000..3c483d6
--- /dev/null
+++ b/tests/Assist/src/com/android/test/assist/AssistInteractionSessionService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.test.assist;
+
+import android.os.Bundle;
+import android.service.voice.VoiceInteractionSession;
+import android.service.voice.VoiceInteractionSessionService;
+
+public class AssistInteractionSessionService extends VoiceInteractionSessionService {
+    @Override
+    public VoiceInteractionSession onNewSession(Bundle args) {
+        return new AssistInteractionSession(this);
+    }
+}
diff --git a/tests/Assist/src/com/android/test/assist/AssistRecognitionService.java b/tests/Assist/src/com/android/test/assist/AssistRecognitionService.java
new file mode 100644
index 0000000..6e5faa1
--- /dev/null
+++ b/tests/Assist/src/com/android/test/assist/AssistRecognitionService.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.test.assist;
+
+import android.content.Intent;
+import android.speech.RecognitionService;
+
+/**
+ * Stub recognition service needed to be a complete voice interactor.
+ */
+public class AssistRecognitionService extends RecognitionService {
+
+    @Override
+    protected void onStartListening(Intent recognizerIntent, Callback listener) {
+    }
+
+    @Override
+    protected void onCancel(Callback listener) {
+    }
+
+    @Override
+    protected void onStopListening(Callback listener) {
+    }
+}
diff --git a/tests/Assist/src/com/android/test/assist/ScrimView.java b/tests/Assist/src/com/android/test/assist/ScrimView.java
new file mode 100644
index 0000000..1b7387b
--- /dev/null
+++ b/tests/Assist/src/com/android/test/assist/ScrimView.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.test.assist;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class ScrimView extends View {
+
+    public ScrimView(Context context) {
+        super(context);
+    }
+
+    public ScrimView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ScrimView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+}
diff --git a/tests/Assistant/Android.mk b/tests/CameraPrewarmTest/Android.mk
similarity index 81%
copy from tests/Assistant/Android.mk
copy to tests/CameraPrewarmTest/Android.mk
index bf8cc29..b6316f0 100644
--- a/tests/Assistant/Android.mk
+++ b/tests/CameraPrewarmTest/Android.mk
@@ -3,7 +3,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_PACKAGE_NAME := Assistant
+LOCAL_PACKAGE_NAME := CameraPrewarmTest
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_CERTIFICATE := platform
diff --git a/tests/CameraPrewarmTest/AndroidManifest.xml b/tests/CameraPrewarmTest/AndroidManifest.xml
new file mode 100644
index 0000000..eb40200
--- /dev/null
+++ b/tests/CameraPrewarmTest/AndroidManifest.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.google.android.test.cameraprewarm">
+    <application android:label="@string/activity_title">
+
+        <activity android:name=".CameraActivity"
+                android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.media.action.STILL_IMAGE_CAMERA_SECURE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name=".SecureCameraActivity"
+                android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <action android:name="android.media.action.STILL_IMAGE_CAMERA_SECURE" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
+        <receiver android:name=".PrewarmReceiver" >
+            <intent-filter>
+                <action android:name="android.media.action.STILL_IMAGE_CAMERA_PREWARM" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.media.action.STILL_IMAGE_CAMERA_COOLDOWN" />
+            </intent-filter>
+        </receiver>
+
+    </application>
+</manifest>
diff --git a/tests/CameraPrewarmTest/res/layout/camera_activity.xml b/tests/CameraPrewarmTest/res/layout/camera_activity.xml
new file mode 100644
index 0000000..64437bc
--- /dev/null
+++ b/tests/CameraPrewarmTest/res/layout/camera_activity.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center">
+</LinearLayout>
+
diff --git a/tests/CameraPrewarmTest/res/values/strings.xml b/tests/CameraPrewarmTest/res/values/strings.xml
new file mode 100644
index 0000000..11f7ac7
--- /dev/null
+++ b/tests/CameraPrewarmTest/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<resources>
+    <string name="activity_title">Assistant</string>
+    <string name="search_label">Orilla Search Engine</string>
+</resources>
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
new file mode 100644
index 0000000..4d22234
--- /dev/null
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.google.android.test.cameraprewarm;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.google.android.test.cameraprewarm.R;
+
+public class CameraActivity extends Activity {
+
+    public final static String TAG = "PrewarmTest";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.camera_activity);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+        Log.i(TAG, "Activity created");
+    }
+}
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/PrewarmReceiver.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/PrewarmReceiver.java
new file mode 100644
index 0000000..d49f96d
--- /dev/null
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/PrewarmReceiver.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.google.android.test.cameraprewarm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.MediaStore;
+import android.util.Log;
+
+public class PrewarmReceiver extends BroadcastReceiver {
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getAction().equals(MediaStore.ACTION_STILL_IMAGE_CAMERA_PREWARM)) {
+            Log.i(CameraActivity.TAG, "Prewarm received");
+        } else if (intent.getAction().equals(MediaStore.ACTION_STILL_IMAGE_CAMERA_COOLDOWN)){
+            Log.i(CameraActivity.TAG, "Cooldown received");
+        }
+    }
+}
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
new file mode 100644
index 0000000..530fe00
--- /dev/null
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.google.android.test.cameraprewarm;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.google.android.test.cameraprewarm.R;
+
+public class SecureCameraActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.camera_activity);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        Log.i(CameraActivity.TAG, "Activity created");
+    }
+}
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
index 0ec4d9d..c2f89dd 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -25,7 +25,7 @@
 
 
 LOCAL_PACKAGE_NAME := AppCompatibilityTest
-
+LOCAL_CERTIFICATE := platform
 include $(BUILD_PACKAGE)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/Compatibility/AndroidManifest.xml b/tests/Compatibility/AndroidManifest.xml
index 2884532..8ae5bc5 100644
--- a/tests/Compatibility/AndroidManifest.xml
+++ b/tests/Compatibility/AndroidManifest.xml
@@ -19,7 +19,7 @@
     <application >
         <uses-library android:name="android.test.runner" />
     </application>
-
+    <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <instrumentation
         android:name=".AppCompatibilityRunner"
         android:targetPackage="com.android.compatibilitytest"
diff --git a/tests/Assistant/Android.mk b/tests/LegacyAssistant/Android.mk
similarity index 82%
rename from tests/Assistant/Android.mk
rename to tests/LegacyAssistant/Android.mk
index bf8cc29..0ad48d1 100644
--- a/tests/Assistant/Android.mk
+++ b/tests/LegacyAssistant/Android.mk
@@ -3,7 +3,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_PACKAGE_NAME := Assistant
+LOCAL_PACKAGE_NAME := LegacyAssistant
 
 LOCAL_MODULE_TAGS := tests
 LOCAL_CERTIFICATE := platform
diff --git a/tests/Assistant/AndroidManifest.xml b/tests/LegacyAssistant/AndroidManifest.xml
similarity index 95%
rename from tests/Assistant/AndroidManifest.xml
rename to tests/LegacyAssistant/AndroidManifest.xml
index b5d4d51..7ae51037 100644
--- a/tests/Assistant/AndroidManifest.xml
+++ b/tests/LegacyAssistant/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.google.android.test.assistant">
+    package="com.google.android.test.legacyassistant">
 
     <application android:label="@string/activity_title">
 
diff --git a/tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png b/tests/LegacyAssistant/res/drawable-hdpi/ic_action_assist_activated.png
similarity index 100%
rename from tests/Assistant/res/drawable-hdpi/ic_action_assist_activated.png
rename to tests/LegacyAssistant/res/drawable-hdpi/ic_action_assist_activated.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png b/tests/LegacyAssistant/res/drawable-hdpi/ic_action_assist_normal.png
similarity index 100%
rename from tests/Assistant/res/drawable-hdpi/ic_action_assist_normal.png
rename to tests/LegacyAssistant/res/drawable-hdpi/ic_action_assist_normal.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png b/tests/LegacyAssistant/res/drawable-mdpi/ic_action_assist_activated.png
similarity index 100%
rename from tests/Assistant/res/drawable-mdpi/ic_action_assist_activated.png
rename to tests/LegacyAssistant/res/drawable-mdpi/ic_action_assist_activated.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png b/tests/LegacyAssistant/res/drawable-mdpi/ic_action_assist_normal.png
similarity index 100%
rename from tests/Assistant/res/drawable-mdpi/ic_action_assist_normal.png
rename to tests/LegacyAssistant/res/drawable-mdpi/ic_action_assist_normal.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png b/tests/LegacyAssistant/res/drawable-xhdpi/ic_action_assist_activated.png
similarity index 100%
rename from tests/Assistant/res/drawable-xhdpi/ic_action_assist_activated.png
rename to tests/LegacyAssistant/res/drawable-xhdpi/ic_action_assist_activated.png
Binary files differ
diff --git a/tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png b/tests/LegacyAssistant/res/drawable-xhdpi/ic_action_assist_normal.png
similarity index 100%
rename from tests/Assistant/res/drawable-xhdpi/ic_action_assist_normal.png
rename to tests/LegacyAssistant/res/drawable-xhdpi/ic_action_assist_normal.png
Binary files differ
diff --git a/tests/Assistant/res/drawable/ic_action_assist.xml b/tests/LegacyAssistant/res/drawable/ic_action_assist.xml
similarity index 100%
rename from tests/Assistant/res/drawable/ic_action_assist.xml
rename to tests/LegacyAssistant/res/drawable/ic_action_assist.xml
diff --git a/tests/Assistant/res/layout/assist_intent_activity.xml b/tests/LegacyAssistant/res/layout/assist_intent_activity.xml
similarity index 100%
rename from tests/Assistant/res/layout/assist_intent_activity.xml
rename to tests/LegacyAssistant/res/layout/assist_intent_activity.xml
diff --git a/tests/Assistant/res/values/strings.xml b/tests/LegacyAssistant/res/values/strings.xml
similarity index 100%
rename from tests/Assistant/res/values/strings.xml
rename to tests/LegacyAssistant/res/values/strings.xml
diff --git a/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java b/tests/LegacyAssistant/src/com/google/android/test/legacyassistant/AssistActivity.java
similarity index 89%
rename from tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java
rename to tests/LegacyAssistant/src/com/google/android/test/legacyassistant/AssistActivity.java
index 51894a1..b3dbb15 100644
--- a/tests/Assistant/src/com/google/android/test/assistant/AssistActivity.java
+++ b/tests/LegacyAssistant/src/com/google/android/test/legacyassistant/AssistActivity.java
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package com.google.android.test.assistant;
+package com.google.android.test.legacyassistant;
 
 import android.app.Activity;
 import android.os.Bundle;
-import com.google.android.test.assistant.R;
+import com.google.android.test.legacyassistant.R;
 
 public class AssistActivity extends Activity {
 
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml
new file mode 100644
index 0000000..88bf777
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale0.xml
@@ -0,0 +1,57 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="90" >
+        <group
+            android:scaleX="1.5"
+            android:scaleY="1" >
+            <group
+                android:pivotX="0"
+                android:pivotY="0"
+                android:rotation="-90" >
+                <group
+                    android:scaleX="1.5"
+                    android:scaleY="1" >
+                    <path
+                        android:name="twoLines"
+                        android:fillColor="#FFFF0000"
+                        android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                        android:strokeColor="#FF00FF00"
+                        android:strokeWidth="10" />
+                </group>
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml
new file mode 100644
index 0000000..530c73b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale1.xml
@@ -0,0 +1,52 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="-1"
+        android:scaleY="-1" >
+        <group
+            android:scaleX="-1"
+            android:scaleY="-1" >
+            <group
+                android:pivotX="100"
+                android:pivotY="100"
+                android:rotation="45" >
+                <path
+                    android:name="twoLines"
+                    android:fillColor="#FFFF0000"
+                    android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                    android:strokeColor="#FF00FF00"
+                    android:strokeWidth="10" />
+            </group>
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml
new file mode 100644
index 0000000..200eb61
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale2.xml
@@ -0,0 +1,48 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:scaleX="2"
+        android:scaleY="0.5" >
+        <group
+            android:pivotX="100"
+            android:pivotY="100"
+            android:rotation="45" >
+            <path
+                android:name="twoLines"
+                android:fillColor="#FFFF0000"
+                android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                android:strokeColor="#FF00FF00"
+                android:strokeWidth="10" />
+        </group>
+    </group>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml
new file mode 100644
index 0000000..a40fc9c
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_scale3.xml
@@ -0,0 +1,62 @@
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="64dp"
+    android:viewportHeight="200"
+    android:viewportWidth="200"
+    android:width="64dp" >
+
+    <group>
+        <path
+            android:name="background1"
+            android:fillColor="#FF000000"
+            android:pathData="M 0,0 l 100,0 l 0, 100 l -100, 0 z" />
+        <path
+            android:name="background2"
+            android:fillColor="#FF000000"
+            android:pathData="M 100,100 l 100,0 l 0, 100 l -100, 0 z" />
+    </group>
+    <group
+        android:pivotX="0"
+        android:pivotY="0"
+        android:rotation="45" >
+        <group
+            android:pivotX="0"
+            android:pivotY="0"
+            android:rotation="90" >
+            <group
+                android:scaleX="1.5"
+                android:scaleY="1" >
+                <group
+                    android:pivotX="0"
+                    android:pivotY="0"
+                    android:rotation="-90" >
+                    <group
+                        android:scaleX="1.5"
+                        android:scaleY="1" >
+                        <path
+                            android:name="twoLines"
+                            android:fillColor="#FFFF0000"
+                            android:pathData="M 100, 0 l 0, 100, -100, 0 z"
+                            android:strokeColor="#FF00FF00"
+                            android:strokeWidth="10" />
+                    </group>
+                </group>
+            </group>
+        </group>
+    </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 d029050..b4a93f6 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -65,6 +65,10 @@
             R.drawable.vector_drawable28,
             R.drawable.vector_drawable29,
             R.drawable.vector_drawable30,
+            R.drawable.vector_drawable_scale0,
+            R.drawable.vector_drawable_scale1,
+            R.drawable.vector_drawable_scale2,
+            R.drawable.vector_drawable_scale3,
     };
 
     public static VectorDrawable create(Resources resources, int rid) {
diff --git a/tests/VoiceInteraction/res/layout/main.xml b/tests/VoiceInteraction/res/layout/main.xml
index 3d7a418..092d37d 100644
--- a/tests/VoiceInteraction/res/layout/main.xml
+++ b/tests/VoiceInteraction/res/layout/main.xml
@@ -26,6 +26,14 @@
         android:text="@string/start"
         />
 
+    <com.android.test.voiceinteraction.AsyncStructure
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingTop="64dp"
+            android:paddingBottom="64dp"
+            android:text="@string/asyncStructure"
+            />
+
 </LinearLayout>
 
 
diff --git a/tests/VoiceInteraction/res/layout/test_interaction.xml b/tests/VoiceInteraction/res/layout/test_interaction.xml
index 8c8151d..6209bd08 100644
--- a/tests/VoiceInteraction/res/layout/test_interaction.xml
+++ b/tests/VoiceInteraction/res/layout/test_interaction.xml
@@ -34,32 +34,49 @@
         android:textAppearance="?android:attr/textAppearanceMedium"
         />
 
-    <Button android:id="@+id/complete"
-        android:layout_width="wrap_content"
+    <LinearLayout android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginTop="16dp"
-        android:text="@string/completeVoice"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/complete"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/completeVoice"
+            />
+
+        <Button android:id="@+id/abort"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/abortVoice"
+            />
+
+        <Button android:id="@+id/pick"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/pickVoice"
+            />
+
+    </LinearLayout>
+
+    <LinearLayout android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginBottom="16dp"
+        android:orientation="horizontal">
+
+        <Button android:id="@+id/cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/cancelVoice"
         />
 
-    <Button android:id="@+id/pick"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="@string/pickVoice"
+        <Button android:id="@+id/jump"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/jumpOut"
         />
 
-    <Button android:id="@+id/abort"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="@string/abortVoice"
-        />
-
-    <Button android:id="@+id/cancel"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="16dp"
-        android:text="@string/cancelVoice"
-    />
+    </LinearLayout>
 
 </LinearLayout>
diff --git a/tests/VoiceInteraction/res/values/strings.xml b/tests/VoiceInteraction/res/values/strings.xml
index 5331457..6289929 100644
--- a/tests/VoiceInteraction/res/values/strings.xml
+++ b/tests/VoiceInteraction/res/values/strings.xml
@@ -17,6 +17,7 @@
 <resources>
 
     <string name="start">Start</string>
+    <string name="asyncStructure">(Async structure goes here)</string>
     <string name="confirm">Confirm</string>
     <string name="abort">Abort</string>
     <string name="complete">Complete</string>
@@ -24,5 +25,6 @@
     <string name="completeVoice">Complete Voice</string>
     <string name="pickVoice">Pick Voice</string>
     <string name="cancelVoice">Cancel</string>
+    <string name="jumpOut">Jump out</string>
 
 </resources>
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index bdc1276..8a72341 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -46,6 +46,7 @@
 
     public void setAssistStructure(AssistStructure as) {
         mAssistStructure = as;
+        mAssistStructure.dump();
         mTextRects.clear();
         final int N = as.getWindowNodeCount();
         if (N > 0) {
@@ -55,6 +56,7 @@
                         windowNode.getTop());
             }
         }
+        Log.d(TAG, "Building text rects in " + this + ": found " + mTextRects.size());
         invalidate();
     }
 
@@ -69,10 +71,11 @@
         }
         int left = parentLeft+root.getLeft();
         int top = parentTop+root.getTop();
-        Log.d(TAG, "View " + root.getClassName() + ": " + left + ", " + top);
-        if (root.getText() != null) {
+        if (root.getText() != null || root.getContentDescription() != null) {
             Rect r = new Rect(left, top, left+root.getWidth(), top+root.getHeight());
-            Log.d(TAG, "Text Rect " + r.toShortString() + ": " + root.getText());
+            Log.d(TAG, "View " + root.getClassName() + " " + left + "," + top + " tr "
+                    + r.toShortString() + ": "
+                    + (root.getText() != null ? root.getText() : root.getContentDescription()));
             mTextRects.add(r);
         }
         final int N = root.getChildCount();
@@ -91,6 +94,7 @@
         super.onDraw(canvas);
         getLocationOnScreen(mTmpLocation);
         final int N = mTextRects.size();
+        Log.d(TAG, "Drawing text rects in " + this + ": found " + mTextRects.size());
         for (int i=0; i<N; i++) {
             Rect r = mTextRects.get(i);
             canvas.drawRect(r.left-mTmpLocation[0], r.top-mTmpLocation[1],
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java
new file mode 100644
index 0000000..73e04e5
--- /dev/null
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AsyncStructure.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.voiceinteraction;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewAssistStructure;
+import android.widget.TextView;
+
+/**
+ * Test for asynchronously creating additional assist structure.
+ */
+public class AsyncStructure extends TextView {
+    public AsyncStructure(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    public void onProvideVirtualAssistStructure(ViewAssistStructure structure) {
+        structure.setChildCount(1);
+        final ViewAssistStructure child = structure.asyncNewChild(0);
+        final int width = getWidth();
+        final int height = getHeight();
+        (new Thread() {
+            @Override
+            public void run() {
+                // Simulate taking a long time to build this.
+                try {
+                    sleep(2000);
+                } catch (InterruptedException e) {
+                }
+                child.setClassName(AsyncStructure.class.getName());
+                child.setVisibility(View.VISIBLE);
+                child.setDimens(width / 4, height / 4, 0, 0, width / 2, height / 2);
+                child.setEnabled(true);
+                child.setContentDescription("This is some async content");
+                child.setText("We could have lots and lots of async text!");
+                child.asyncCommit();
+            }
+        }).start();
+    }
+}
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index bc18ca9..3c5c201 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -16,6 +16,7 @@
 
 package com.android.test.voiceinteraction;
 
+import android.app.ActivityManager;
 import android.app.AssistContent;
 import android.app.AssistStructure;
 import android.app.VoiceInteractor;
@@ -69,6 +70,8 @@
     @Override
     public void onCreate(Bundle args, int startFlags) {
         super.onCreate(args);
+        ActivityManager am = getContext().getSystemService(ActivityManager.class);
+        am.setWatchHeapLimit(40*1024*1024);
     }
 
     @Override
@@ -142,7 +145,6 @@
             if (assistContext != null) {
                 mAssistStructure = AssistStructure.getAssistStructure(assistContext);
                 if (mAssistStructure != null) {
-                    mAssistStructure.dump();
                     if (mAssistVisualizer != null) {
                         mAssistVisualizer.setAssistStructure(mAssistStructure);
                     }
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index e195c30..9d24c59 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.app.VoiceInteractor;
 import android.content.ComponentName;
+import android.content.Intent;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionService;
 import android.util.Log;
@@ -37,6 +38,7 @@
     Button mAbortButton;
     Button mCompleteButton;
     Button mPickButton;
+    Button mJumpOutButton;
     Button mCancelButton;
 
     @Override
@@ -64,6 +66,8 @@
         mCompleteButton.setOnClickListener(this);
         mPickButton = (Button)findViewById(R.id.pick);
         mPickButton.setOnClickListener(this);
+        mJumpOutButton = (Button)findViewById(R.id.jump);
+        mJumpOutButton.setOnClickListener(this);
         mCancelButton = (Button)findViewById(R.id.cancel);
         mCancelButton.setOnClickListener(this);
 
@@ -165,6 +169,13 @@
                 }
             };
             mInteractor.submitRequest(req);
+        } else if (v == mJumpOutButton) {
+            Log.i(TAG, "Jump out");
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.addCategory(Intent.CATEGORY_LAUNCHER);
+            intent.setComponent(new ComponentName(this, VoiceInteractionMain.class));
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            startActivity(intent);
         } else if (v == mCancelButton && mCurrentRequest != null) {
             Log.i(TAG, "Cancel request");
             mCurrentRequest.cancel();
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index c5495a5..9956bd7 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -67,7 +67,7 @@
     libziparchive-host
 
 aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER)\"
-aaptCFLAGS += -Wall -Werror
+aaptCFlags += -Wall -Werror
 
 ifeq ($(HOST_OS),linux)
     aaptHostLdLibs += -lrt -ldl -lpthread
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 063b4e6..e4738f5 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -412,7 +412,6 @@
                              int startX, int startY, int endX, int endY, int dX, int dY,
                              int* out_inset)
 {
-    bool opaque_within_inset = true;
     uint8_t max_opacity = 0;
     int inset = 0;
     *out_inset = 0;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 36299c2..beb94fd 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -22,7 +22,7 @@
 
 // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
 
-#if HAVE_PRINTF_ZD
+#if !defined(_WIN32)
 #  define ZD "%zd"
 #  define ZD_TYPE ssize_t
 #  define STATUST(x) x
@@ -3056,7 +3056,6 @@
         const sp<AaptDir>& d = dirs.itemAt(k);
         const String8& dirName = d->getLeaf();
         Vector<String8> startTags;
-        const char* startTag = NULL;
         const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
         if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
             tagAttrPairs = &kLayoutTagAttrPairs;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 941a288..c5fccbf 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -20,7 +20,7 @@
 
 // SSIZE: mingw does not have signed size_t == ssize_t.
 // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
-#if HAVE_PRINTF_ZD
+#if !defined(_WIN32)
 #  define SSIZE(x) x
 #  define STATUST(x) x
 #else
@@ -3167,7 +3167,7 @@
                     if (!validResources[i]) {
                         sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
                         if (c != NULL) {
-                            fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
+                            fprintf(stderr, "%s: no entries written for %s/%s (0x%08zx)\n", log_prefix,
                                     String8(typeName).string(), String8(c->getName()).string(),
                                     Res_MAKEID(p->getAssignedId() - 1, ti, i));
                         }
@@ -4526,7 +4526,6 @@
                     const KeyedVector<String16, Item>& bag = e->getBag();
                     const size_t bagCount = bag.size();
                     for (size_t bi = 0; bi < bagCount; bi++) {
-                        const Item& item = bag.valueAt(bi);
                         const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
                         const int sdkLevel = getPublicAttributeSdkLevel(attrId);
                         if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index a18e9f1..9908c44 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -13,7 +13,7 @@
 #include "ResourceTable.h"
 
 // SSIZE: mingw does not have signed size_t == ssize_t.
-#if HAVE_PRINTF_ZD
+#if !defined(_WIN32)
 #  define ZD "%zd"
 #  define ZD_TYPE ssize_t
 #  define SSIZE(x) x
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index d2cd2d6..6902a30 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -18,7 +18,7 @@
 
 // SSIZE: mingw does not have signed size_t == ssize_t.
 // STATUST: mingw does seem to redefine UNKNOWN_ERROR from our enum value, so a cast is necessary.
-#if HAVE_PRINTF_ZD
+#if !defined(_WIN32)
 #  define SSIZE(x) x
 #  define STATUST(x) x
 #else
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
new file mode 100644
index 0000000..0622dc6
--- /dev/null
+++ b/tools/aapt2/Android.mk
@@ -0,0 +1,147 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This tool is prebuilt if we're doing an app-only build.
+ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+
+# ==========================================================
+# Setup some common variables for the different build
+# targets here.
+# ==========================================================
+LOCAL_PATH:= $(call my-dir)
+
+main := Main.cpp
+sources := \
+	BigBuffer.cpp \
+	BinaryResourceParser.cpp \
+	BindingXmlPullParser.cpp \
+	ConfigDescription.cpp \
+	Files.cpp \
+	Flag.cpp \
+	JavaClassGenerator.cpp \
+	Linker.cpp \
+	Locale.cpp \
+	Logger.cpp \
+	ManifestParser.cpp \
+	ManifestValidator.cpp \
+	Png.cpp \
+	ResChunkPullParser.cpp \
+	Resolver.cpp \
+	Resource.cpp \
+	ResourceParser.cpp \
+	ResourceTable.cpp \
+	ResourceValues.cpp \
+	SdkConstants.cpp \
+	StringPool.cpp \
+	TableFlattener.cpp \
+	Util.cpp \
+	ScopedXmlPullParser.cpp \
+	SourceXmlPullParser.cpp \
+	XliffXmlPullParser.cpp \
+	XmlFlattener.cpp
+
+testSources := \
+	BigBuffer_test.cpp \
+	BindingXmlPullParser_test.cpp \
+	Compat_test.cpp \
+	ConfigDescription_test.cpp \
+	JavaClassGenerator_test.cpp \
+	Linker_test.cpp \
+	Locale_test.cpp \
+	ManifestParser_test.cpp \
+	Maybe_test.cpp \
+	ResourceParser_test.cpp \
+	Resource_test.cpp \
+	ResourceTable_test.cpp \
+	ScopedXmlPullParser_test.cpp \
+	StringPiece_test.cpp \
+	StringPool_test.cpp \
+	Util_test.cpp \
+	XliffXmlPullParser_test.cpp \
+	XmlFlattener_test.cpp
+
+cIncludes := \
+	external/libpng \
+	external/libz
+
+hostLdLibs :=
+
+hostStaticLibs := \
+	libandroidfw \
+	libutils \
+	liblog \
+	libcutils \
+	libexpat \
+	libziparchive-host \
+	libpng
+
+ifneq ($(strip $(USE_MINGW)),)
+	hostStaticLibs += libz
+else
+	hostLdLibs += -lz
+endif
+
+cFlags := -Wall -Werror -Wno-unused-parameter -UNDEBUG
+cppFlags := -std=c++11 -Wno-missing-field-initializers
+
+# ==========================================================
+# Build the host static library: libaapt2
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libaapt2
+
+LOCAL_SRC_FILES := $(sources)
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_CFLAGS += $(cFlags)
+LOCAL_CPPFLAGS += $(cppFlags)
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# ==========================================================
+# Build the host tests: libaapt2_tests
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libaapt2_tests
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(testSources)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_STATIC_LIBRARIES += libaapt2 $(hostStaticLibs)
+LOCAL_LDLIBS += $(hostLdLibs)
+LOCAL_CFLAGS += $(cFlags)
+LOCAL_CPPFLAGS += $(cppFlags)
+
+include $(BUILD_HOST_NATIVE_TEST)
+
+# ==========================================================
+# Build the host executable: aapt2
+# ==========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := aapt2
+
+LOCAL_SRC_FILES := $(main)
+
+LOCAL_C_INCLUDES += $(cIncludes)
+LOCAL_STATIC_LIBRARIES += libaapt2 $(hostStaticLibs)
+LOCAL_LDLIBS += $(hostLdLibs)
+LOCAL_CFLAGS += $(cFlags)
+LOCAL_CPPFLAGS += $(cppFlags)
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/tools/aapt2/AppInfo.h
similarity index 62%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to tools/aapt2/AppInfo.h
index c9fd989..30047f7 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/tools/aapt2/AppInfo.h
@@ -13,7 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+#ifndef AAPT_APP_INFO_H
+#define AAPT_APP_INFO_H
+
+#include <string>
+
+namespace aapt {
+
+/**
+ * Holds basic information about the app being built. Most of this information
+ * will come from the app's AndroidManifest.
+ */
+struct AppInfo {
+    /**
+     * App's package name.
+     */
+    std::u16string package;
+};
+
+} // namespace aapt
+
+#endif // AAPT_APP_INFO_H
diff --git a/tools/aapt2/BigBuffer.cpp b/tools/aapt2/BigBuffer.cpp
new file mode 100644
index 0000000..8f57172
--- /dev/null
+++ b/tools/aapt2/BigBuffer.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BigBuffer.h"
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+namespace aapt {
+
+void* BigBuffer::nextBlockImpl(size_t size) {
+    if (!mBlocks.empty()) {
+        Block& block = mBlocks.back();
+        if (block.mBlockSize - block.size >= size) {
+            void* outBuffer = block.buffer.get() + block.size;
+            block.size += size;
+            mSize += size;
+            return outBuffer;
+        }
+    }
+
+    const size_t actualSize = std::max(mBlockSize, size);
+
+    Block block = {};
+
+    // Zero-allocate the block's buffer.
+    block.buffer = std::unique_ptr<uint8_t[]>(new uint8_t[actualSize]());
+    assert(block.buffer);
+
+    block.size = size;
+    block.mBlockSize = actualSize;
+
+    mBlocks.push_back(std::move(block));
+    mSize += size;
+    return mBlocks.back().buffer.get();
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/BigBuffer.h b/tools/aapt2/BigBuffer.h
new file mode 100644
index 0000000..8b6569c
--- /dev/null
+++ b/tools/aapt2/BigBuffer.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_BIG_BUFFER_H
+#define AAPT_BIG_BUFFER_H
+
+#include <cassert>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * Inspired by protobuf's ZeroCopyOutputStream, offers blocks of memory
+ * in which to write without knowing the full size of the entire payload.
+ * This is essentially a list of memory blocks. As one fills up, another
+ * block is allocated and appended to the end of the list.
+ */
+class BigBuffer {
+public:
+    /**
+     * A contiguous block of allocated memory.
+     */
+    struct Block {
+        /**
+         * Pointer to the memory.
+         */
+        std::unique_ptr<uint8_t[]> buffer;
+
+        /**
+         * Size of memory that is currently occupied. The actual
+         * allocation may be larger.
+         */
+        size_t size;
+
+    private:
+        friend class BigBuffer;
+
+        /**
+         * The size of the memory block allocation.
+         */
+        size_t mBlockSize;
+    };
+
+    typedef std::vector<Block>::const_iterator const_iterator;
+
+    /**
+     * Create a BigBuffer with block allocation sizes
+     * of blockSize.
+     */
+    BigBuffer(size_t blockSize);
+
+    BigBuffer(const BigBuffer&) = delete; // No copying.
+
+    BigBuffer(BigBuffer&& rhs);
+
+    /**
+     * Number of occupied bytes in all the allocated blocks.
+     */
+    size_t size() const;
+
+    /**
+     * Returns a pointer to an array of T, where T is
+     * a POD type. The elements are zero-initialized.
+     */
+    template <typename T>
+    T* nextBlock(size_t count = 1);
+
+    /**
+     * Moves the specified BigBuffer into this one. When this method
+     * returns, buffer is empty.
+     */
+    void appendBuffer(BigBuffer&& buffer);
+
+    /**
+     * Pads the block with 'bytes' bytes of zero values.
+     */
+    void pad(size_t bytes);
+
+    /**
+     * Pads the block so that it aligns on a 4 byte boundary.
+     */
+    void align4();
+
+    const_iterator begin() const;
+    const_iterator end() const;
+
+private:
+    /**
+     * Returns a pointer to a buffer of the requested size.
+     * The buffer is zero-initialized.
+     */
+    void* nextBlockImpl(size_t size);
+
+    size_t mBlockSize;
+    size_t mSize;
+    std::vector<Block> mBlocks;
+};
+
+inline BigBuffer::BigBuffer(size_t blockSize) : mBlockSize(blockSize), mSize(0) {
+}
+
+inline BigBuffer::BigBuffer(BigBuffer&& rhs) :
+        mBlockSize(rhs.mBlockSize), mSize(rhs.mSize), mBlocks(std::move(rhs.mBlocks)) {
+}
+
+inline size_t BigBuffer::size() const {
+    return mSize;
+}
+
+template <typename T>
+inline T* BigBuffer::nextBlock(size_t count) {
+    assert(count != 0);
+    return reinterpret_cast<T*>(nextBlockImpl(sizeof(T) * count));
+}
+
+inline void BigBuffer::appendBuffer(BigBuffer&& buffer) {
+    std::move(buffer.mBlocks.begin(), buffer.mBlocks.end(), std::back_inserter(mBlocks));
+    mSize += buffer.mSize;
+    buffer.mBlocks.clear();
+    buffer.mSize = 0;
+}
+
+inline void BigBuffer::pad(size_t bytes) {
+    nextBlock<char>(bytes);
+}
+
+inline void BigBuffer::align4() {
+    const size_t unaligned = mSize % 4;
+    if (unaligned != 0) {
+        pad(4 - unaligned);
+    }
+}
+
+inline BigBuffer::const_iterator BigBuffer::begin() const {
+    return mBlocks.begin();
+}
+
+inline BigBuffer::const_iterator BigBuffer::end() const {
+    return mBlocks.end();
+}
+
+} // namespace aapt
+
+#endif // AAPT_BIG_BUFFER_H
diff --git a/tools/aapt2/BigBuffer_test.cpp b/tools/aapt2/BigBuffer_test.cpp
new file mode 100644
index 0000000..01ee8d7
--- /dev/null
+++ b/tools/aapt2/BigBuffer_test.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BigBuffer.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(BigBufferTest, AllocateSingleBlock) {
+    BigBuffer buffer(4);
+
+    EXPECT_NE(nullptr, buffer.nextBlock<char>(2));
+    EXPECT_EQ(2u, buffer.size());
+}
+
+TEST(BigBufferTest, ReturnSameBlockIfNextAllocationFits) {
+    BigBuffer buffer(16);
+
+    char* b1 = buffer.nextBlock<char>(8);
+    EXPECT_NE(nullptr, b1);
+
+    char* b2 = buffer.nextBlock<char>(4);
+    EXPECT_NE(nullptr, b2);
+
+    EXPECT_EQ(b1 + 8, b2);
+}
+
+TEST(BigBufferTest, AllocateExactSizeBlockIfLargerThanBlockSize) {
+    BigBuffer buffer(16);
+
+    EXPECT_NE(nullptr, buffer.nextBlock<char>(32));
+    EXPECT_EQ(32u, buffer.size());
+}
+
+TEST(BigBufferTest, AppendAndMoveBlock) {
+    BigBuffer buffer(16);
+
+    uint32_t* b1 = buffer.nextBlock<uint32_t>();
+    ASSERT_NE(nullptr, b1);
+    *b1 = 33;
+
+    {
+        BigBuffer buffer2(16);
+        b1 = buffer2.nextBlock<uint32_t>();
+        ASSERT_NE(nullptr, b1);
+        *b1 = 44;
+
+        buffer.appendBuffer(std::move(buffer2));
+        EXPECT_EQ(0u, buffer2.size());
+        EXPECT_EQ(buffer2.begin(), buffer2.end());
+    }
+
+    EXPECT_EQ(2 * sizeof(uint32_t), buffer.size());
+
+    auto b = buffer.begin();
+    ASSERT_NE(b, buffer.end());
+    ASSERT_EQ(sizeof(uint32_t), b->size);
+    ASSERT_EQ(33u, *reinterpret_cast<uint32_t*>(b->buffer.get()));
+    ++b;
+
+    ASSERT_NE(b, buffer.end());
+    ASSERT_EQ(sizeof(uint32_t), b->size);
+    ASSERT_EQ(44u, *reinterpret_cast<uint32_t*>(b->buffer.get()));
+    ++b;
+
+    ASSERT_EQ(b, buffer.end());
+}
+
+TEST(BigBufferTest, PadAndAlignProperly) {
+    BigBuffer buffer(16);
+
+    ASSERT_NE(buffer.nextBlock<char>(2), nullptr);
+    ASSERT_EQ(2u, buffer.size());
+    buffer.pad(2);
+    ASSERT_EQ(4u, buffer.size());
+    buffer.align4();
+    ASSERT_EQ(4u, buffer.size());
+    buffer.pad(2);
+    ASSERT_EQ(6u, buffer.size());
+    buffer.align4();
+    ASSERT_EQ(8u, buffer.size());
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/BinaryResourceParser.cpp b/tools/aapt2/BinaryResourceParser.cpp
new file mode 100644
index 0000000..3eb96bc
--- /dev/null
+++ b/tools/aapt2/BinaryResourceParser.cpp
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BinaryResourceParser.h"
+#include "Logger.h"
+#include "ResChunkPullParser.h"
+#include "ResourceParser.h"
+#include "ResourceTable.h"
+#include "ResourceTypeExtensions.h"
+#include "ResourceValues.h"
+#include "Source.h"
+#include "Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <androidfw/TypeWrappers.h>
+#include <map>
+#include <string>
+
+namespace aapt {
+
+using namespace android;
+
+template <typename T>
+inline static const T* convertTo(const ResChunk_header* chunk) {
+    if (chunk->headerSize < sizeof(T)) {
+        return nullptr;
+    }
+    return reinterpret_cast<const T*>(chunk);
+}
+
+inline static const uint8_t* getChunkData(const ResChunk_header& chunk) {
+    return reinterpret_cast<const uint8_t*>(&chunk) + chunk.headerSize;
+}
+
+inline static size_t getChunkDataLen(const ResChunk_header& chunk) {
+    return chunk.size - chunk.headerSize;
+}
+
+/*
+ * Visitor that converts a reference's resource ID to a resource name,
+ * given a mapping from resource ID to resource name.
+ */
+struct ReferenceIdToNameVisitor : ValueVisitor {
+    ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceName>& cache) : mCache(cache) {
+    }
+
+    void visit(Reference& reference, ValueVisitorArgs&) override {
+        idToName(reference);
+    }
+
+    void visit(Attribute& attr, ValueVisitorArgs&) override {
+        for (auto& entry : attr.symbols) {
+            idToName(entry.symbol);
+        }
+    }
+
+    void visit(Style& style, ValueVisitorArgs&) override {
+        if (style.parent.id.isValid()) {
+            idToName(style.parent);
+        }
+
+        for (auto& entry : style.entries) {
+            idToName(entry.key);
+            entry.value->accept(*this, {});
+        }
+    }
+
+    void visit(Styleable& styleable, ValueVisitorArgs&) override {
+        for (auto& attr : styleable.entries) {
+            idToName(attr);
+        }
+    }
+
+    void visit(Array& array, ValueVisitorArgs&) override {
+        for (auto& item : array.items) {
+            item->accept(*this, {});
+        }
+    }
+
+    void visit(Plural& plural, ValueVisitorArgs&) override {
+        for (auto& item : plural.values) {
+            if (item) {
+                item->accept(*this, {});
+            }
+        }
+    }
+
+private:
+    void idToName(Reference& reference) {
+        if (!reference.id.isValid()) {
+            return;
+        }
+
+        auto cacheIter = mCache.find(reference.id);
+        if (cacheIter == std::end(mCache)) {
+            Logger::note() << "failed to find " << reference.id << std::endl;
+        } else {
+            reference.name = cacheIter->second;
+            reference.id = 0;
+        }
+    }
+
+    const std::map<ResourceId, ResourceName>& mCache;
+};
+
+
+BinaryResourceParser::BinaryResourceParser(std::shared_ptr<ResourceTable> table,
+                                           const Source& source,
+                                           const void* data,
+                                           size_t len) :
+        mTable(table), mSource(source), mData(data), mDataLen(len) {
+}
+
+bool BinaryResourceParser::parse() {
+    ResChunkPullParser parser(mData, mDataLen);
+
+    bool error = false;
+    while(ResChunkPullParser::isGoodEvent(parser.next())) {
+        if (parser.getChunk()->type != android::RES_TABLE_TYPE) {
+            Logger::warn(mSource)
+                    << "unknown chunk of type '"
+                    << parser.getChunk()->type
+                    << "'."
+                    << std::endl;
+            continue;
+        }
+
+        error |= !parseTable(parser.getChunk());
+    }
+
+    if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) {
+        Logger::error(mSource)
+                << "bad document: "
+                << parser.getLastError()
+                << "."
+                << std::endl;
+        return false;
+    }
+    return !error;
+}
+
+bool BinaryResourceParser::getSymbol(const void* data, ResourceNameRef* outSymbol) {
+    if (!mSymbolEntries || mSymbolEntryCount == 0) {
+        return false;
+    }
+
+    if (reinterpret_cast<uintptr_t>(data) < reinterpret_cast<uintptr_t>(mData)) {
+        return false;
+    }
+
+    // We only support 32 bit offsets right now.
+    const uintptr_t offset = reinterpret_cast<uintptr_t>(data) -
+            reinterpret_cast<uintptr_t>(mData);
+    if (offset > std::numeric_limits<uint32_t>::max()) {
+        return false;
+    }
+
+    for (size_t i = 0; i < mSymbolEntryCount; i++) {
+        if (mSymbolEntries[i].offset == offset) {
+            // This offset is a symbol!
+            const StringPiece16 str = util::getString(mSymbolPool,
+                                                      mSymbolEntries[i].stringIndex);
+            StringPiece16 typeStr;
+            ResourceParser::extractResourceName(str, &outSymbol->package, &typeStr,
+                                                &outSymbol->entry);
+            const ResourceType* type = parseResourceType(typeStr);
+            if (!type) {
+                return false;
+            }
+            outSymbol->type = *type;
+
+            // Since we scan the symbol table in order, we can start looking for the
+            // next symbol from this point.
+            mSymbolEntryCount -= i + 1;
+            mSymbolEntries += i + 1;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool BinaryResourceParser::parseSymbolTable(const ResChunk_header* chunk) {
+    const SymbolTable_header* symbolTableHeader = convertTo<SymbolTable_header>(chunk);
+    if (!symbolTableHeader) {
+        Logger::error(mSource)
+                << "could not parse chunk as SymbolTable_header."
+                << std::endl;
+        return false;
+    }
+
+    const size_t entrySizeBytes = symbolTableHeader->count * sizeof(SymbolTable_entry);
+    if (entrySizeBytes > getChunkDataLen(symbolTableHeader->header)) {
+        Logger::error(mSource)
+                << "entries extend beyond chunk."
+                << std::endl;
+        return false;
+    }
+
+    mSymbolEntries = reinterpret_cast<const SymbolTable_entry*>(
+            getChunkData(symbolTableHeader->header));
+    mSymbolEntryCount = symbolTableHeader->count;
+
+    ResChunkPullParser parser(getChunkData(symbolTableHeader->header) + entrySizeBytes,
+                              getChunkDataLen(symbolTableHeader->header) - entrySizeBytes);
+    if (!ResChunkPullParser::isGoodEvent(parser.next())) {
+        Logger::error(mSource)
+                << "failed to parse chunk: "
+                << parser.getLastError()
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    if (parser.getChunk()->type != android::RES_STRING_POOL_TYPE) {
+        Logger::error(mSource)
+                << "expected Symbol string pool."
+                << std::endl;
+        return false;
+    }
+
+    if (mSymbolPool.setTo(parser.getChunk(), parser.getChunk()->size) != NO_ERROR) {
+        Logger::error(mSource)
+                << "failed to parse symbol string pool with code: "
+                << mSymbolPool.getError()
+                << "."
+                << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool BinaryResourceParser::parseTable(const ResChunk_header* chunk) {
+    const ResTable_header* tableHeader = convertTo<ResTable_header>(chunk);
+    if (!tableHeader) {
+        Logger::error(mSource)
+                << "could not parse chunk as ResTable_header."
+                << std::endl;
+        return false;
+    }
+
+    ResChunkPullParser parser(getChunkData(tableHeader->header),
+                              getChunkDataLen(tableHeader->header));
+    while (ResChunkPullParser::isGoodEvent(parser.next())) {
+        switch (parser.getChunk()->type) {
+        case android::RES_STRING_POOL_TYPE:
+            if (mValuePool.getError() == NO_INIT) {
+                if (mValuePool.setTo(parser.getChunk(), parser.getChunk()->size) !=
+                        NO_ERROR) {
+                    Logger::error(mSource)
+                            << "failed to parse value string pool with code: "
+                            << mValuePool.getError()
+                            << "."
+                            << std::endl;
+                    return false;
+                }
+
+                // Reserve some space for the strings we are going to add.
+                mTable->getValueStringPool().hintWillAdd(
+                        mValuePool.size(), mValuePool.styleCount());
+            } else {
+                Logger::warn(mSource)
+                    << "unexpected string pool."
+                    << std::endl;
+            }
+            break;
+
+        case RES_TABLE_SYMBOL_TABLE_TYPE:
+            if (!parseSymbolTable(parser.getChunk())) {
+                return false;
+            }
+            break;
+
+        case RES_TABLE_SOURCE_POOL_TYPE: {
+            if (mSourcePool.setTo(getChunkData(*parser.getChunk()),
+                        getChunkDataLen(*parser.getChunk())) != NO_ERROR) {
+                Logger::error(mSource)
+                        << "failed to parse source pool with code: "
+                        << mSourcePool.getError()
+                        << "."
+                        << std::endl;
+                return false;
+            }
+            break;
+        }
+
+        case android::RES_TABLE_PACKAGE_TYPE:
+            if (!parsePackage(parser.getChunk())) {
+                return false;
+            }
+            break;
+
+        default:
+            Logger::warn(mSource)
+                << "unexpected chunk of type "
+                << parser.getChunk()->type
+                << "."
+                << std::endl;
+            break;
+        }
+    }
+
+    if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) {
+        Logger::error(mSource)
+            << "bad resource table: " << parser.getLastError()
+            << "."
+            << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool BinaryResourceParser::parsePackage(const ResChunk_header* chunk) {
+    if (mValuePool.getError() != NO_ERROR) {
+        Logger::error(mSource)
+                << "no value string pool for ResTable."
+                << std::endl;
+        return false;
+    }
+
+    const ResTable_package* packageHeader = convertTo<ResTable_package>(chunk);
+    if (!packageHeader) {
+        Logger::error(mSource)
+                << "could not parse chunk as ResTable_header."
+                << std::endl;
+        return false;
+    }
+
+    if (mTable->getPackageId() == ResourceTable::kUnsetPackageId) {
+        // This is the first time the table has it's package ID set.
+        mTable->setPackageId(packageHeader->id);
+    } else if (mTable->getPackageId() != packageHeader->id) {
+        Logger::error(mSource)
+                << "ResTable_package has package ID "
+                << std::hex << packageHeader->id << std::dec
+                << " but ResourceTable has package ID "
+                << std::hex << mTable->getPackageId() << std::dec
+                << std::endl;
+        return false;
+    }
+
+    size_t len = strnlen16(reinterpret_cast<const char16_t*>(packageHeader->name),
+            sizeof(packageHeader->name) / sizeof(packageHeader->name[0]));
+    mTable->setPackage(StringPiece16(reinterpret_cast<const char16_t*>(packageHeader->name), len));
+
+    ResChunkPullParser parser(getChunkData(packageHeader->header),
+                              getChunkDataLen(packageHeader->header));
+    while (ResChunkPullParser::isGoodEvent(parser.next())) {
+        switch (parser.getChunk()->type) {
+        case android::RES_STRING_POOL_TYPE:
+            if (mTypePool.getError() == NO_INIT) {
+                if (mTypePool.setTo(parser.getChunk(), parser.getChunk()->size) !=
+                        NO_ERROR) {
+                    Logger::error(mSource)
+                            << "failed to parse type string pool with code "
+                            << mTypePool.getError()
+                            << "."
+                            << std::endl;
+                    return false;
+                }
+            } else if (mKeyPool.getError() == NO_INIT) {
+                if (mKeyPool.setTo(parser.getChunk(), parser.getChunk()->size) !=
+                        NO_ERROR) {
+                    Logger::error(mSource)
+                            << "failed to parse key string pool with code "
+                            << mKeyPool.getError()
+                            << "."
+                            << std::endl;
+                    return false;
+                }
+            } else {
+                Logger::warn(mSource)
+                        << "unexpected string pool."
+                        << std::endl;
+            }
+            break;
+
+        case android::RES_TABLE_TYPE_SPEC_TYPE:
+            if (!parseTypeSpec(parser.getChunk())) {
+                return false;
+            }
+            break;
+
+        case android::RES_TABLE_TYPE_TYPE:
+            if (!parseType(parser.getChunk())) {
+                return false;
+            }
+            break;
+
+        default:
+            Logger::warn(mSource)
+                    << "unexpected chunk of type "
+                    << parser.getChunk()->type
+                    << "."
+                    << std::endl;
+            break;
+        }
+    }
+
+    if (parser.getEvent() == ResChunkPullParser::Event::BadDocument) {
+        Logger::error(mSource)
+                << "bad package: "
+                << parser.getLastError()
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    // Now go through the table and change resource ID references to
+    // symbolic references.
+
+    ReferenceIdToNameVisitor visitor(mIdIndex);
+    for (auto& type : *mTable) {
+        for (auto& entry : type->entries) {
+            for (auto& configValue : entry->values) {
+                configValue.value->accept(visitor, {});
+            }
+        }
+    }
+    return true;
+}
+
+bool BinaryResourceParser::parseTypeSpec(const ResChunk_header* chunk) {
+    if (mTypePool.getError() != NO_ERROR) {
+        Logger::error(mSource)
+                << "no type string pool available for ResTable_typeSpec."
+                << std::endl;
+        return false;
+    }
+
+    const ResTable_typeSpec* typeSpec = convertTo<ResTable_typeSpec>(chunk);
+    if (!typeSpec) {
+        Logger::error(mSource)
+                << "could not parse chunk as ResTable_typeSpec."
+                << std::endl;
+        return false;
+    }
+
+    if (typeSpec->id == 0) {
+        Logger::error(mSource)
+                << "ResTable_typeSpec has invalid id: "
+                << typeSpec->id
+                << "."
+                << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool BinaryResourceParser::parseType(const ResChunk_header* chunk) {
+    if (mTypePool.getError() != NO_ERROR) {
+        Logger::error(mSource)
+                << "no type string pool available for ResTable_typeSpec."
+                << std::endl;
+        return false;
+    }
+
+    if (mKeyPool.getError() != NO_ERROR) {
+        Logger::error(mSource)
+                << "no key string pool available for ResTable_type."
+                << std::endl;
+        return false;
+    }
+
+    const ResTable_type* type = convertTo<ResTable_type>(chunk);
+    if (!type) {
+        Logger::error(mSource)
+                << "could not parse chunk as ResTable_type."
+                << std::endl;
+        return false;
+    }
+
+    if (type->id == 0) {
+        Logger::error(mSource)
+                << "ResTable_type has invalid id: "
+                << type->id
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    const ConfigDescription config(type->config);
+    const StringPiece16 typeName = util::getString(mTypePool, type->id - 1);
+
+    const ResourceType* parsedType = parseResourceType(typeName);
+    if (!parsedType) {
+        Logger::error(mSource)
+                << "invalid type name '"
+                << typeName
+                << "' for type with ID "
+                << uint32_t(type->id)
+                << "." << std::endl;
+        return false;
+    }
+
+    android::TypeVariant tv(type);
+    for (auto it = tv.beginEntries(); it != tv.endEntries(); ++it) {
+        if (!*it) {
+            continue;
+        }
+
+        const ResTable_entry* entry = *it;
+        const ResourceName name = {
+                mTable->getPackage(),
+                *parsedType,
+                util::getString(mKeyPool, entry->key.index).toString()
+        };
+
+        const ResourceId resId = { mTable->getPackageId(), type->id, it.index() };
+
+        std::unique_ptr<Value> resourceValue;
+        const ResTable_entry_source* sourceBlock = nullptr;
+        if (entry->flags & ResTable_entry::FLAG_COMPLEX) {
+            const ResTable_map_entry* mapEntry = static_cast<const ResTable_map_entry*>(entry);
+            if (mapEntry->size - sizeof(*mapEntry) == sizeof(*sourceBlock)) {
+                const uint8_t* data = reinterpret_cast<const uint8_t*>(mapEntry);
+                data += mapEntry->size - sizeof(*sourceBlock);
+                sourceBlock = reinterpret_cast<const ResTable_entry_source*>(data);
+            }
+
+            // TODO(adamlesinski): Check that the entry count is valid.
+            resourceValue = parseMapEntry(name, config, mapEntry);
+        } else {
+            if (entry->size - sizeof(*entry) == sizeof(*sourceBlock)) {
+                const uint8_t* data = reinterpret_cast<const uint8_t*>(entry);
+                data += entry->size - sizeof(*sourceBlock);
+                sourceBlock = reinterpret_cast<const ResTable_entry_source*>(data);
+            }
+
+            const Res_value* value = reinterpret_cast<const Res_value*>(
+                    reinterpret_cast<const uint8_t*>(entry) + entry->size);
+            resourceValue = parseValue(name, config, value, entry->flags);
+        }
+
+        if (!resourceValue) {
+            // TODO(adamlesinski): For now this is ok, but it really shouldn't be.
+            continue;
+        }
+
+        SourceLine source = mSource.line(0);
+        if (sourceBlock) {
+            size_t len;
+            const char* str = mSourcePool.string8At(sourceBlock->pathIndex, &len);
+            if (str) {
+                source.path.assign(str, len);
+            }
+            source.line = sourceBlock->line;
+        }
+
+        if (!mTable->addResource(name, config, source, std::move(resourceValue))) {
+            return false;
+        }
+
+        if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
+            if (!mTable->markPublic(name, resId, mSource.line(0))) {
+                return false;
+            }
+        }
+
+        // Add this resource name->id mapping to the index so
+        // that we can resolve all ID references to name references.
+        auto cacheIter = mIdIndex.find(resId);
+        if (cacheIter == mIdIndex.end()) {
+            mIdIndex.insert({ resId, name });
+        }
+    }
+    return true;
+}
+
+std::unique_ptr<Item> BinaryResourceParser::parseValue(const ResourceNameRef& name,
+                                                       const ConfigDescription& config,
+                                                       const Res_value* value,
+                                                       uint16_t flags) {
+    if (value->dataType == Res_value::TYPE_STRING) {
+        StringPiece16 str = util::getString(mValuePool, value->data);
+
+        const ResStringPool_span* spans = mValuePool.styleAt(value->data);
+        if (spans != nullptr) {
+            StyleString styleStr = { str.toString() };
+            while (spans->name.index != ResStringPool_span::END) {
+                styleStr.spans.push_back(Span{
+                        util::getString(mValuePool, spans->name.index).toString(),
+                        spans->firstChar,
+                        spans->lastChar
+                });
+                spans++;
+            }
+            return util::make_unique<StyledString>(
+                    mTable->getValueStringPool().makeRef(
+                            styleStr, StringPool::Context{1, config}));
+        } else {
+            // There are no styles associated with this string, so treat it as
+            // a simple string.
+            return util::make_unique<String>(
+                    mTable->getValueStringPool().makeRef(
+                            str, StringPool::Context{1, config}));
+        }
+    }
+
+    if (value->dataType == Res_value::TYPE_REFERENCE ||
+            value->dataType == Res_value::TYPE_ATTRIBUTE) {
+        const Reference::Type type = (value->dataType == Res_value::TYPE_REFERENCE) ?
+                    Reference::Type::kResource : Reference::Type::kAttribute;
+
+        if (value->data != 0) {
+            // This is a normal reference.
+            return util::make_unique<Reference>(value->data, type);
+        }
+
+        // This reference has an invalid ID. Check if it is an unresolved symbol.
+        ResourceNameRef symbol;
+        if (getSymbol(&value->data, &symbol)) {
+            return util::make_unique<Reference>(symbol, type);
+        }
+
+        // This is not an unresolved symbol, so it must be the magic @null reference.
+        Res_value nullType = {};
+        nullType.dataType = Res_value::TYPE_NULL;
+        nullType.data = Res_value::DATA_NULL_UNDEFINED;
+        return util::make_unique<BinaryPrimitive>(nullType);
+    }
+
+    if (value->dataType == ExtendedTypes::TYPE_SENTINEL) {
+        return util::make_unique<Sentinel>();
+    }
+
+    if (value->dataType == ExtendedTypes::TYPE_RAW_STRING) {
+        return util::make_unique<RawString>(
+                mTable->getValueStringPool().makeRef(util::getString(mValuePool, value->data),
+                                                    StringPool::Context{ 1, config }));
+    }
+
+    if (name.type == ResourceType::kId ||
+            (value->dataType == Res_value::TYPE_NULL &&
+            value->data == Res_value::DATA_NULL_UNDEFINED &&
+            (flags & ResTable_entry::FLAG_WEAK) != 0)) {
+        return util::make_unique<Id>();
+    }
+
+    // Treat this as a raw binary primitive.
+    return util::make_unique<BinaryPrimitive>(*value);
+}
+
+std::unique_ptr<Value> BinaryResourceParser::parseMapEntry(const ResourceNameRef& name,
+                                                           const ConfigDescription& config,
+                                                           const ResTable_map_entry* map) {
+    switch (name.type) {
+        case ResourceType::kStyle:
+            return parseStyle(name, config, map);
+        case ResourceType::kAttr:
+            return parseAttr(name, config, map);
+        case ResourceType::kArray:
+            return parseArray(name, config, map);
+        case ResourceType::kStyleable:
+            return parseStyleable(name, config, map);
+        case ResourceType::kPlurals:
+            return parsePlural(name, config, map);
+        default:
+            break;
+    }
+    return {};
+}
+
+std::unique_ptr<Style> BinaryResourceParser::parseStyle(const ResourceNameRef& name,
+                                                        const ConfigDescription& config,
+                                                        const ResTable_map_entry* map) {
+    std::unique_ptr<Style> style = util::make_unique<Style>();
+    if (map->parent.ident == 0) {
+        // The parent is either not set or it is an unresolved symbol.
+        // Check to see if it is a symbol.
+        ResourceNameRef symbol;
+        if (getSymbol(&map->parent.ident, &symbol)) {
+            style->parent.name = symbol.toResourceName();
+        }
+    } else {
+         // The parent is a regular reference to a resource.
+        style->parent.id = map->parent.ident;
+    }
+
+    for (const ResTable_map& mapEntry : map) {
+        style->entries.emplace_back();
+        Style::Entry& styleEntry = style->entries.back();
+
+        if (mapEntry.name.ident == 0) {
+            // The map entry's key (attribute) is not set. This must be
+            // a symbol reference, so resolve it.
+            ResourceNameRef symbol;
+            bool result = getSymbol(&mapEntry.name.ident, &symbol);
+            assert(result);
+            styleEntry.key.name = symbol.toResourceName();
+        } else {
+            // The map entry's key (attribute) is a regular reference.
+            styleEntry.key.id = mapEntry.name.ident;
+        }
+
+        // Parse the attribute's value.
+        styleEntry.value = parseValue(name, config, &mapEntry.value, 0);
+        assert(styleEntry.value);
+    }
+    return style;
+}
+
+std::unique_ptr<Attribute> BinaryResourceParser::parseAttr(const ResourceNameRef& name,
+                                                           const ConfigDescription& config,
+                                                           const ResTable_map_entry* map) {
+    const bool isWeak = (map->flags & ResTable_entry::FLAG_WEAK) != 0;
+    std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
+
+    // First we must discover what type of attribute this is. Find the type mask.
+    auto typeMaskIter = std::find_if(begin(map), end(map), [](const ResTable_map& entry) -> bool {
+        return entry.name.ident == ResTable_map::ATTR_TYPE;
+    });
+
+    if (typeMaskIter != end(map)) {
+        attr->typeMask = typeMaskIter->value.data;
+    }
+
+    if (attr->typeMask & (ResTable_map::TYPE_ENUM | ResTable_map::TYPE_FLAGS)) {
+        for (const ResTable_map& mapEntry : map) {
+            if (Res_INTERNALID(mapEntry.name.ident)) {
+                continue;
+            }
+
+            attr->symbols.push_back(Attribute::Symbol{
+                    Reference(mapEntry.name.ident),
+                    mapEntry.value.data
+            });
+        }
+    }
+
+    // TODO(adamlesinski): Find min, max, i80n, etc attributes.
+    return attr;
+}
+
+std::unique_ptr<Array> BinaryResourceParser::parseArray(const ResourceNameRef& name,
+                                                        const ConfigDescription& config,
+                                                        const ResTable_map_entry* map) {
+    std::unique_ptr<Array> array = util::make_unique<Array>();
+    for (const ResTable_map& mapEntry : map) {
+        array->items.push_back(parseValue(name, config, &mapEntry.value, 0));
+    }
+    return array;
+}
+
+std::unique_ptr<Styleable> BinaryResourceParser::parseStyleable(const ResourceNameRef& name,
+                                                                const ConfigDescription& config,
+                                                                const ResTable_map_entry* map) {
+    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+    for (const ResTable_map& mapEntry : map) {
+        styleable->entries.emplace_back(mapEntry.name.ident);
+    }
+    return styleable;
+}
+
+std::unique_ptr<Plural> BinaryResourceParser::parsePlural(const ResourceNameRef& name,
+                                                          const ConfigDescription& config,
+                                                          const ResTable_map_entry* map) {
+    std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+    for (const ResTable_map& mapEntry : map) {
+        std::unique_ptr<Item> item = parseValue(name, config, &mapEntry.value, 0);
+
+        switch (mapEntry.name.ident) {
+            case android::ResTable_map::ATTR_ZERO:
+                plural->values[Plural::Zero] = std::move(item);
+                break;
+            case android::ResTable_map::ATTR_ONE:
+                plural->values[Plural::One] = std::move(item);
+                break;
+            case android::ResTable_map::ATTR_TWO:
+                plural->values[Plural::Two] = std::move(item);
+                break;
+            case android::ResTable_map::ATTR_FEW:
+                plural->values[Plural::Few] = std::move(item);
+                break;
+            case android::ResTable_map::ATTR_MANY:
+                plural->values[Plural::Many] = std::move(item);
+                break;
+            case android::ResTable_map::ATTR_OTHER:
+                plural->values[Plural::Other] = std::move(item);
+                break;
+        }
+    }
+    return plural;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/BinaryResourceParser.h b/tools/aapt2/BinaryResourceParser.h
new file mode 100644
index 0000000..9268078
--- /dev/null
+++ b/tools/aapt2/BinaryResourceParser.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_BINARY_RESOURCE_PARSER_H
+#define AAPT_BINARY_RESOURCE_PARSER_H
+
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Source.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <string>
+
+namespace aapt {
+
+struct SymbolTable_entry;
+
+/*
+ * Parses a binary resource table (resources.arsc) and adds the entries
+ * to a ResourceTable. This is different than the libandroidfw ResTable
+ * in that it scans the table from top to bottom and doesn't require
+ * support for random access. It is also able to parse non-runtime
+ * chunks and types.
+ */
+class BinaryResourceParser {
+public:
+    /*
+     * Creates a parser, which will read `len` bytes from `data`, and
+     * add any resources parsed to `table`. `source` is for logging purposes.
+     */
+    BinaryResourceParser(std::shared_ptr<ResourceTable> table, const Source& source,
+                         const void* data, size_t len);
+
+    BinaryResourceParser(const BinaryResourceParser&) = delete; // No copy.
+
+    /*
+     * Parses the binary resource table and returns true if successful.
+     */
+    bool parse();
+
+private:
+    // Helper method to retrieve the symbol name for a given table offset specified
+    // as a pointer.
+    bool getSymbol(const void* data, ResourceNameRef* outSymbol);
+
+    bool parseTable(const android::ResChunk_header* chunk);
+    bool parseSymbolTable(const android::ResChunk_header* chunk);
+
+    // Looks up the resource ID in the reference and converts it to a name if available.
+    bool idToName(Reference* reference);
+
+    bool parsePackage(const android::ResChunk_header* chunk);
+    bool parseTypeSpec(const android::ResChunk_header* chunk);
+    bool parseType(const android::ResChunk_header* chunk);
+
+    std::unique_ptr<Item> parseValue(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::Res_value* value, uint16_t flags);
+
+    std::unique_ptr<Value> parseMapEntry(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::ResTable_map_entry* map);
+
+    std::unique_ptr<Style> parseStyle(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::ResTable_map_entry* map);
+
+    std::unique_ptr<Attribute> parseAttr(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::ResTable_map_entry* map);
+
+    std::unique_ptr<Array> parseArray(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::ResTable_map_entry* map);
+
+    std::unique_ptr<Plural> parsePlural(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::ResTable_map_entry* map);
+
+    std::unique_ptr<Styleable> parseStyleable(const ResourceNameRef& name,
+            const ConfigDescription& config, const android::ResTable_map_entry* map);
+
+    std::shared_ptr<ResourceTable> mTable;
+
+    const Source mSource;
+
+    const void* mData;
+    const size_t mDataLen;
+
+    // The package name of the resource table.
+    std::u16string mPackage;
+
+    // The array of symbol entries. Each element points to an offset
+    // in the table and an index into the symbol table string pool.
+    const SymbolTable_entry* mSymbolEntries = nullptr;
+
+    // Number of symbol entries.
+    size_t mSymbolEntryCount = 0;
+
+    // The symbol table string pool. Holds the names of symbols
+    // referenced in this table but not defined nor resolved to an
+    // ID.
+    android::ResStringPool mSymbolPool;
+
+    // The source string pool. Resource entries may have an extra
+    // field that points into this string pool, which denotes where
+    // the resource was parsed from originally.
+    android::ResStringPool mSourcePool;
+
+    // The standard value string pool for resource values.
+    android::ResStringPool mValuePool;
+
+    // The string pool that holds the names of the types defined
+    // in this table.
+    android::ResStringPool mTypePool;
+
+    // The string pool that holds the names of the entries defined
+    // in this table.
+    android::ResStringPool mKeyPool;
+
+    // A mapping of resource ID to resource name. When we finish parsing
+    // we use this to convert all resource IDs to symbolic references.
+    std::map<ResourceId, ResourceName> mIdIndex;
+};
+
+} // namespace aapt
+
+namespace android {
+
+/**
+ * Iterator functionality for ResTable_map_entry.
+ */
+
+inline const ResTable_map* begin(const ResTable_map_entry* map) {
+    return reinterpret_cast<const ResTable_map*>(
+            reinterpret_cast<const uint8_t*>(map) + map->size);
+}
+
+inline const ResTable_map* end(const ResTable_map_entry* map) {
+    return reinterpret_cast<const ResTable_map*>(
+            reinterpret_cast<const uint8_t*>(map) + map->size) + map->count;
+}
+
+} // namespace android
+
+#endif // AAPT_BINARY_RESOURCE_PARSER_H
diff --git a/tools/aapt2/BindingXmlPullParser.cpp b/tools/aapt2/BindingXmlPullParser.cpp
new file mode 100644
index 0000000..58b96e8
--- /dev/null
+++ b/tools/aapt2/BindingXmlPullParser.cpp
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BindingXmlPullParser.h"
+#include "Util.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+constexpr const char16_t* kBindingNamespaceUri = u"http://schemas.android.com/apk/binding";
+constexpr const char16_t* kAndroidNamespaceUri = u"http://schemas.android.com/apk/res/android";
+constexpr const char16_t* kVariableTagName = u"variable";
+constexpr const char* kBindingTagPrefix = "android:binding_";
+
+BindingXmlPullParser::BindingXmlPullParser(const std::shared_ptr<XmlPullParser>& parser) :
+        mParser(parser), mOverride(false), mNextTagId(0) {
+}
+
+bool BindingXmlPullParser::readVariableDeclaration() {
+    VarDecl var;
+
+    const auto endAttrIter = mParser->endAttributes();
+    for (auto attrIter = mParser->beginAttributes(); attrIter != endAttrIter; ++attrIter) {
+        if (!attrIter->namespaceUri.empty()) {
+            continue;
+        }
+
+        if (attrIter->name == u"name") {
+            var.name = util::utf16ToUtf8(attrIter->value);
+        } else if (attrIter->name == u"type") {
+            var.type = util::utf16ToUtf8(attrIter->value);
+        }
+    }
+
+    XmlPullParser::skipCurrentElement(mParser.get());
+
+    if (var.name.empty()) {
+        mLastError = "variable declaration missing name";
+        return false;
+    }
+
+    if (var.type.empty()) {
+        mLastError = "variable declaration missing type";
+        return false;
+    }
+
+    mVarDecls.push_back(std::move(var));
+    return true;
+}
+
+bool BindingXmlPullParser::readExpressions() {
+    mOverride = true;
+    std::vector<XmlPullParser::Attribute> expressions;
+    std::string idValue;
+
+    const auto endAttrIter = mParser->endAttributes();
+    for (auto attr = mParser->beginAttributes(); attr != endAttrIter; ++attr) {
+        if (attr->namespaceUri == kAndroidNamespaceUri && attr->name == u"id") {
+            idValue = util::utf16ToUtf8(attr->value);
+        } else {
+            StringPiece16 value = util::trimWhitespace(attr->value);
+            if (util::stringStartsWith<char16_t>(value, u"@{") &&
+                    util::stringEndsWith<char16_t>(value, u"}")) {
+                // This is attribute's value is an expression of the form
+                // @{expression}. We need to capture the expression inside.
+                expressions.push_back(XmlPullParser::Attribute{
+                        attr->namespaceUri,
+                        attr->name,
+                        value.substr(2, value.size() - 3).toString()
+                });
+            } else {
+                // This is a normal attribute, use as is.
+                mAttributes.emplace_back(*attr);
+            }
+        }
+    }
+
+    // Check if we have any expressions.
+    if (!expressions.empty()) {
+        // We have expressions, so let's assign the target a tag number
+        // and add it to our targets list.
+        int32_t targetId = mNextTagId++;
+        mTargets.push_back(Target{
+                util::utf16ToUtf8(mParser->getElementName()),
+                idValue,
+                targetId,
+                std::move(expressions)
+        });
+
+        std::stringstream numGen;
+        numGen << kBindingTagPrefix << targetId;
+        mAttributes.push_back(XmlPullParser::Attribute{
+                std::u16string(kAndroidNamespaceUri),
+                std::u16string(u"tag"),
+                util::utf8ToUtf16(numGen.str())
+        });
+    }
+    return true;
+}
+
+XmlPullParser::Event BindingXmlPullParser::next() {
+    // Clear old state in preparation for the next event.
+    mOverride = false;
+    mAttributes.clear();
+
+    while (true) {
+        Event event = mParser->next();
+        if (event == Event::kStartElement) {
+            if (mParser->getElementNamespace().empty() &&
+                    mParser->getElementName() == kVariableTagName) {
+                // This is a variable tag. Record data from it, and
+                // then discard the entire element.
+                if (!readVariableDeclaration()) {
+                    // mLastError is set, so getEvent will return kBadDocument.
+                    return getEvent();
+                }
+                continue;
+            } else {
+                // Check for expressions of the form @{} in attribute text.
+                const auto endAttrIter = mParser->endAttributes();
+                for (auto attr = mParser->beginAttributes(); attr != endAttrIter; ++attr) {
+                    StringPiece16 value = util::trimWhitespace(attr->value);
+                    if (util::stringStartsWith<char16_t>(value, u"@{") &&
+                            util::stringEndsWith<char16_t>(value, u"}")) {
+                        if (!readExpressions()) {
+                            return getEvent();
+                        }
+                        break;
+                    }
+                }
+            }
+        } else if (event == Event::kStartNamespace || event == Event::kEndNamespace) {
+            if (mParser->getNamespaceUri() == kBindingNamespaceUri) {
+                // Skip binding namespace tags.
+                continue;
+            }
+        }
+        return event;
+    }
+    return Event::kBadDocument;
+}
+
+bool BindingXmlPullParser::writeToFile(std::ostream& out) const {
+    out << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+    out << "<Layout directory=\"\" layout=\"\" layoutId=\"\">\n";
+
+    // Write the variables.
+    out << "  <Variables>\n";
+    for (const VarDecl& v : mVarDecls) {
+        out << "    <entries name=\"" << v.name << "\" type=\"" << v.type << "\"/>\n";
+    }
+    out << "  </Variables>\n";
+
+    // Write the imports.
+
+    std::stringstream tagGen;
+
+    // Write the targets.
+    out << "  <Targets>\n";
+    for (const Target& t : mTargets) {
+        tagGen.str({});
+        tagGen << kBindingTagPrefix << t.tagId;
+        out << "    <Target boundClass=\"" << t.className << "\" id=\"" << t.id
+            << "\" tag=\"" << tagGen.str() << "\">\n";
+        out << "      <Expressions>\n";
+        for (const XmlPullParser::Attribute& a : t.expressions) {
+            out << "        <Expression attribute=\"" << a.namespaceUri << ":" << a.name
+                << "\" text=\"" << a.value << "\"/>\n";
+        }
+        out << "      </Expressions>\n";
+        out << "    </Target>\n";
+    }
+    out << "  </Targets>\n";
+
+    out << "</Layout>\n";
+    return bool(out);
+}
+
+XmlPullParser::const_iterator BindingXmlPullParser::beginAttributes() const {
+    if (mOverride) {
+        return mAttributes.begin();
+    }
+    return mParser->beginAttributes();
+}
+
+XmlPullParser::const_iterator BindingXmlPullParser::endAttributes() const {
+    if (mOverride) {
+        return mAttributes.end();
+    }
+    return mParser->endAttributes();
+}
+
+size_t BindingXmlPullParser::getAttributeCount() const {
+    if (mOverride) {
+        return mAttributes.size();
+    }
+    return mParser->getAttributeCount();
+}
+
+XmlPullParser::Event BindingXmlPullParser::getEvent() const {
+    if (!mLastError.empty()) {
+        return Event::kBadDocument;
+    }
+    return mParser->getEvent();
+}
+
+const std::string& BindingXmlPullParser::getLastError() const {
+    if (!mLastError.empty()) {
+        return mLastError;
+    }
+    return mParser->getLastError();
+}
+
+const std::u16string& BindingXmlPullParser::getComment() const {
+    return mParser->getComment();
+}
+
+size_t BindingXmlPullParser::getLineNumber() const {
+    return mParser->getLineNumber();
+}
+
+size_t BindingXmlPullParser::getDepth() const {
+    return mParser->getDepth();
+}
+
+const std::u16string& BindingXmlPullParser::getText() const {
+    return mParser->getText();
+}
+
+const std::u16string& BindingXmlPullParser::getNamespacePrefix() const {
+    return mParser->getNamespacePrefix();
+}
+
+const std::u16string& BindingXmlPullParser::getNamespaceUri() const {
+    return mParser->getNamespaceUri();
+}
+
+const std::u16string& BindingXmlPullParser::getElementNamespace() const {
+    return mParser->getElementNamespace();
+}
+
+const std::u16string& BindingXmlPullParser::getElementName() const {
+    return mParser->getElementName();
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/BindingXmlPullParser.h b/tools/aapt2/BindingXmlPullParser.h
new file mode 100644
index 0000000..c892b09
--- /dev/null
+++ b/tools/aapt2/BindingXmlPullParser.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_BINDING_XML_PULL_PARSER_H
+#define AAPT_BINDING_XML_PULL_PARSER_H
+
+#include "XmlPullParser.h"
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+namespace aapt {
+
+class BindingXmlPullParser : public XmlPullParser {
+public:
+    BindingXmlPullParser(const std::shared_ptr<XmlPullParser>& parser);
+    BindingXmlPullParser(const BindingXmlPullParser& rhs) = delete;
+
+    Event getEvent() const override;
+    const std::string& getLastError() const override;
+    Event next() override;
+
+    const std::u16string& getComment() const override;
+    size_t getLineNumber() const override;
+    size_t getDepth() const override;
+
+    const std::u16string& getText() const override;
+
+    const std::u16string& getNamespacePrefix() const override;
+    const std::u16string& getNamespaceUri() const override;
+
+    const std::u16string& getElementNamespace() const override;
+    const std::u16string& getElementName() const override;
+
+    const_iterator beginAttributes() const override;
+    const_iterator endAttributes() const override;
+    size_t getAttributeCount() const override;
+
+    bool writeToFile(std::ostream& out) const;
+
+private:
+    struct VarDecl {
+        std::string name;
+        std::string type;
+    };
+
+    struct Import {
+        std::string name;
+        std::string type;
+    };
+
+    struct Target {
+        std::string className;
+        std::string id;
+        int32_t tagId;
+
+        std::vector<XmlPullParser::Attribute> expressions;
+    };
+
+    bool readVariableDeclaration();
+    bool readExpressions();
+
+    std::shared_ptr<XmlPullParser> mParser;
+    std::string mLastError;
+    bool mOverride;
+    std::vector<XmlPullParser::Attribute> mAttributes;
+    std::vector<VarDecl> mVarDecls;
+    std::vector<Target> mTargets;
+    int32_t mNextTagId;
+};
+
+} // namespace aapt
+
+#endif // AAPT_BINDING_XML_PULL_PARSER_H
diff --git a/tools/aapt2/BindingXmlPullParser_test.cpp b/tools/aapt2/BindingXmlPullParser_test.cpp
new file mode 100644
index 0000000..28edcb6
--- /dev/null
+++ b/tools/aapt2/BindingXmlPullParser_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SourceXmlPullParser.h"
+#include "BindingXmlPullParser.h"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+constexpr const char16_t* kAndroidNamespaceUri = u"http://schemas.android.com/apk/res/android";
+
+TEST(BindingXmlPullParserTest, SubstituteBindingExpressionsWithTag) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+          << "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+          << "              xmlns:bind=\"http://schemas.android.com/apk/binding\"\n"
+          << "              android:id=\"@+id/content\">\n"
+          << "  <variable name=\"user\" type=\"com.android.test.User\"/>\n"
+          << "  <TextView android:text=\"@{user.name}\" android:layout_width=\"wrap_content\"\n"
+          << "            android:layout_height=\"wrap_content\"/>\n"
+          << "</LinearLayout>\n";
+    std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
+    BindingXmlPullParser parser(sourceParser);
+
+    ASSERT_EQ(XmlPullParser::Event::kStartNamespace, parser.next());
+    EXPECT_EQ(std::u16string(u"http://schemas.android.com/apk/res/android"),
+              parser.getNamespaceUri());
+
+    ASSERT_EQ(XmlPullParser::Event::kStartElement, parser.next());
+    EXPECT_EQ(std::u16string(u"LinearLayout"), parser.getElementName());
+
+    while (parser.next() == XmlPullParser::Event::kText) {}
+
+    ASSERT_EQ(XmlPullParser::Event::kStartElement, parser.getEvent());
+    EXPECT_EQ(std::u16string(u"TextView"), parser.getElementName());
+
+    ASSERT_EQ(3u, parser.getAttributeCount());
+    const auto endAttr = parser.endAttributes();
+    EXPECT_NE(endAttr, parser.findAttribute(kAndroidNamespaceUri, u"layout_width"));
+    EXPECT_NE(endAttr, parser.findAttribute(kAndroidNamespaceUri, u"layout_height"));
+    EXPECT_NE(endAttr, parser.findAttribute(kAndroidNamespaceUri, u"tag"));
+
+    while (parser.next() == XmlPullParser::Event::kText) {}
+
+    ASSERT_EQ(XmlPullParser::Event::kEndElement, parser.getEvent());
+
+    while (parser.next() == XmlPullParser::Event::kText) {}
+
+    ASSERT_EQ(XmlPullParser::Event::kEndElement, parser.getEvent());
+    ASSERT_EQ(XmlPullParser::Event::kEndNamespace, parser.next());
+}
+
+TEST(BindingXmlPullParserTest, GenerateVariableDeclarations) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+          << "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+          << "              xmlns:bind=\"http://schemas.android.com/apk/binding\"\n"
+          << "              android:id=\"@+id/content\">\n"
+          << "  <variable name=\"user\" type=\"com.android.test.User\"/>\n"
+          << "</LinearLayout>\n";
+    std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
+    BindingXmlPullParser parser(sourceParser);
+
+    while (XmlPullParser::isGoodEvent(parser.next())) {
+        ASSERT_NE(XmlPullParser::Event::kBadDocument, parser.getEvent());
+    }
+
+    std::stringstream output;
+    ASSERT_TRUE(parser.writeToFile(output));
+
+    std::string result = output.str();
+    EXPECT_NE(std::string::npos,
+              result.find("<entries name=\"user\" type=\"com.android.test.User\"/>"));
+}
+
+TEST(BindingXmlPullParserTest, FailOnMissingNameOrTypeInVariableDeclaration) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+          << "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+          << "              xmlns:bind=\"http://schemas.android.com/apk/binding\"\n"
+          << "              android:id=\"@+id/content\">\n"
+          << "  <variable name=\"user\"/>\n"
+          << "</LinearLayout>\n";
+    std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
+    BindingXmlPullParser parser(sourceParser);
+
+    while (XmlPullParser::isGoodEvent(parser.next())) {}
+
+    EXPECT_EQ(XmlPullParser::Event::kBadDocument, parser.getEvent());
+    EXPECT_FALSE(parser.getLastError().empty());
+}
+
+
+} // namespace aapt
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/tools/aapt2/Compat_test.cpp
similarity index 67%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to tools/aapt2/Compat_test.cpp
index c9fd989..96aee44 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/tools/aapt2/Compat_test.cpp
@@ -13,7 +13,21 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+#include <gtest/gtest.h>
+
+namespace aapt {
+
+TEST(CompatTest, VersionAttributesInStyle) {
+}
+
+TEST(CompatTest, VersionAttributesInXML) {
+}
+
+TEST(CompatTest, DoNotOverrideExistingVersionedFiles) {
+}
+
+TEST(CompatTest, VersionAttributesInStyleWithCorrectPrecedence) {
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
new file mode 100644
index 0000000..6ddf94a
--- /dev/null
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigDescription.h"
+#include "Locale.h"
+#include "SdkConstants.h"
+#include "StringPiece.h"
+#include "Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+using android::ResTable_config;
+
+static const char* kWildcardName = "any";
+
+static bool parseMcc(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->mcc = 0;
+        return true;
+    }
+    const char* c = name;
+    if (tolower(*c) != 'm') return false;
+    c++;
+    if (tolower(*c) != 'c') return false;
+    c++;
+    if (tolower(*c) != 'c') return false;
+    c++;
+
+    const char* val = c;
+
+    while (*c >= '0' && *c <= '9') {
+        c++;
+    }
+    if (*c != 0) return false;
+    if (c-val != 3) return false;
+
+    int d = atoi(val);
+    if (d != 0) {
+        if (out) out->mcc = d;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseMnc(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->mcc = 0;
+        return true;
+    }
+    const char* c = name;
+    if (tolower(*c) != 'm') return false;
+    c++;
+    if (tolower(*c) != 'n') return false;
+    c++;
+    if (tolower(*c) != 'c') return false;
+    c++;
+
+    const char* val = c;
+
+    while (*c >= '0' && *c <= '9') {
+        c++;
+    }
+    if (*c != 0) return false;
+    if (c-val == 0 || c-val > 3) return false;
+
+    if (out) {
+        out->mnc = atoi(val);
+        if (out->mnc == 0) {
+            out->mnc = ACONFIGURATION_MNC_ZERO;
+        }
+    }
+
+    return true;
+}
+
+static bool parseLayoutDirection(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_ANY;
+        return true;
+    } else if (strcmp(name, "ldltr") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_LTR;
+        return true;
+    } else if (strcmp(name, "ldrtl") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_LAYOUTDIR)
+                | ResTable_config::LAYOUTDIR_RTL;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseScreenLayoutSize(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_ANY;
+        return true;
+    } else if (strcmp(name, "small") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_SMALL;
+        return true;
+    } else if (strcmp(name, "normal") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_NORMAL;
+        return true;
+    } else if (strcmp(name, "large") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_LARGE;
+        return true;
+    } else if (strcmp(name, "xlarge") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENSIZE)
+                | ResTable_config::SCREENSIZE_XLARGE;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseScreenLayoutLong(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+                | ResTable_config::SCREENLONG_ANY;
+        return true;
+    } else if (strcmp(name, "long") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+                | ResTable_config::SCREENLONG_YES;
+        return true;
+    } else if (strcmp(name, "notlong") == 0) {
+        if (out) out->screenLayout =
+                (out->screenLayout&~ResTable_config::MASK_SCREENLONG)
+                | ResTable_config::SCREENLONG_NO;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseOrientation(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->orientation = out->ORIENTATION_ANY;
+        return true;
+    } else if (strcmp(name, "port") == 0) {
+        if (out) out->orientation = out->ORIENTATION_PORT;
+        return true;
+    } else if (strcmp(name, "land") == 0) {
+        if (out) out->orientation = out->ORIENTATION_LAND;
+        return true;
+    } else if (strcmp(name, "square") == 0) {
+        if (out) out->orientation = out->ORIENTATION_SQUARE;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseUiModeType(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->uiMode =
+                (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+                | ResTable_config::UI_MODE_TYPE_ANY;
+        return true;
+    } else if (strcmp(name, "desk") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_DESK;
+        return true;
+    } else if (strcmp(name, "car") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_CAR;
+        return true;
+    } else if (strcmp(name, "television") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_TELEVISION;
+        return true;
+    } else if (strcmp(name, "appliance") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_APPLIANCE;
+        return true;
+    } else if (strcmp(name, "watch") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_TYPE)
+              | ResTable_config::UI_MODE_TYPE_WATCH;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseUiModeNight(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->uiMode =
+                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+                | ResTable_config::UI_MODE_NIGHT_ANY;
+        return true;
+    } else if (strcmp(name, "night") == 0) {
+        if (out) out->uiMode =
+                (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+                | ResTable_config::UI_MODE_NIGHT_YES;
+        return true;
+    } else if (strcmp(name, "notnight") == 0) {
+      if (out) out->uiMode =
+              (out->uiMode&~ResTable_config::MASK_UI_MODE_NIGHT)
+              | ResTable_config::UI_MODE_NIGHT_NO;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseDensity(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->density = ResTable_config::DENSITY_DEFAULT;
+        return true;
+    }
+
+    if (strcmp(name, "anydpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_ANY;
+        return true;
+    }
+
+    if (strcmp(name, "nodpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_NONE;
+        return true;
+    }
+
+    if (strcmp(name, "ldpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_LOW;
+        return true;
+    }
+
+    if (strcmp(name, "mdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_MEDIUM;
+        return true;
+    }
+
+    if (strcmp(name, "tvdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_TV;
+        return true;
+    }
+
+    if (strcmp(name, "hdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_HIGH;
+        return true;
+    }
+
+    if (strcmp(name, "xhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XHIGH;
+        return true;
+    }
+
+    if (strcmp(name, "xxhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XXHIGH;
+        return true;
+    }
+
+    if (strcmp(name, "xxxhdpi") == 0) {
+        if (out) out->density = ResTable_config::DENSITY_XXXHIGH;
+        return true;
+    }
+
+    char* c = (char*)name;
+    while (*c >= '0' && *c <= '9') {
+        c++;
+    }
+
+    // check that we have 'dpi' after the last digit.
+    if (toupper(c[0]) != 'D' ||
+            toupper(c[1]) != 'P' ||
+            toupper(c[2]) != 'I' ||
+            c[3] != 0) {
+        return false;
+    }
+
+    // temporarily replace the first letter with \0 to
+    // use atoi.
+    char tmp = c[0];
+    c[0] = '\0';
+
+    int d = atoi(name);
+    c[0] = tmp;
+
+    if (d != 0) {
+        if (out) out->density = d;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseTouchscreen(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_ANY;
+        return true;
+    } else if (strcmp(name, "notouch") == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_NOTOUCH;
+        return true;
+    } else if (strcmp(name, "stylus") == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_STYLUS;
+        return true;
+    } else if (strcmp(name, "finger") == 0) {
+        if (out) out->touchscreen = out->TOUCHSCREEN_FINGER;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseKeysHidden(const char* name, ResTable_config* out) {
+    uint8_t mask = 0;
+    uint8_t value = 0;
+    if (strcmp(name, kWildcardName) == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_ANY;
+    } else if (strcmp(name, "keysexposed") == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_NO;
+    } else if (strcmp(name, "keyshidden") == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_YES;
+    } else if (strcmp(name, "keyssoft") == 0) {
+        mask = ResTable_config::MASK_KEYSHIDDEN;
+        value = ResTable_config::KEYSHIDDEN_SOFT;
+    }
+
+    if (mask != 0) {
+        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseKeyboard(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->keyboard = out->KEYBOARD_ANY;
+        return true;
+    } else if (strcmp(name, "nokeys") == 0) {
+        if (out) out->keyboard = out->KEYBOARD_NOKEYS;
+        return true;
+    } else if (strcmp(name, "qwerty") == 0) {
+        if (out) out->keyboard = out->KEYBOARD_QWERTY;
+        return true;
+    } else if (strcmp(name, "12key") == 0) {
+        if (out) out->keyboard = out->KEYBOARD_12KEY;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseNavHidden(const char* name, ResTable_config* out) {
+    uint8_t mask = 0;
+    uint8_t value = 0;
+    if (strcmp(name, kWildcardName) == 0) {
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_ANY;
+    } else if (strcmp(name, "navexposed") == 0) {
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_NO;
+    } else if (strcmp(name, "navhidden") == 0) {
+        mask = ResTable_config::MASK_NAVHIDDEN;
+        value = ResTable_config::NAVHIDDEN_YES;
+    }
+
+    if (mask != 0) {
+        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseNavigation(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) out->navigation = out->NAVIGATION_ANY;
+        return true;
+    } else if (strcmp(name, "nonav") == 0) {
+        if (out) out->navigation = out->NAVIGATION_NONAV;
+        return true;
+    } else if (strcmp(name, "dpad") == 0) {
+        if (out) out->navigation = out->NAVIGATION_DPAD;
+        return true;
+    } else if (strcmp(name, "trackball") == 0) {
+        if (out) out->navigation = out->NAVIGATION_TRACKBALL;
+        return true;
+    } else if (strcmp(name, "wheel") == 0) {
+        if (out) out->navigation = out->NAVIGATION_WHEEL;
+        return true;
+    }
+
+    return false;
+}
+
+static bool parseScreenSize(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->screenWidth = out->SCREENWIDTH_ANY;
+            out->screenHeight = out->SCREENHEIGHT_ANY;
+        }
+        return true;
+    }
+
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || *x != 'x') return false;
+    std::string xName(name, x-name);
+    x++;
+
+    const char* y = x;
+    while (*y >= '0' && *y <= '9') y++;
+    if (y == name || *y != 0) return false;
+    std::string yName(x, y-x);
+
+    uint16_t w = (uint16_t)atoi(xName.c_str());
+    uint16_t h = (uint16_t)atoi(yName.c_str());
+    if (w < h) {
+        return false;
+    }
+
+    if (out) {
+        out->screenWidth = w;
+        out->screenHeight = h;
+    }
+
+    return true;
+}
+
+static bool parseSmallestScreenWidthDp(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->smallestScreenWidthDp = out->SCREENWIDTH_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 's') return false;
+    name++;
+    if (*name != 'w') return false;
+    name++;
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+    std::string xName(name, x-name);
+
+    if (out) {
+        out->smallestScreenWidthDp = (uint16_t)atoi(xName.c_str());
+    }
+
+    return true;
+}
+
+static bool parseScreenWidthDp(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->screenWidthDp = out->SCREENWIDTH_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 'w') return false;
+    name++;
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+    std::string xName(name, x-name);
+
+    if (out) {
+        out->screenWidthDp = (uint16_t)atoi(xName.c_str());
+    }
+
+    return true;
+}
+
+static bool parseScreenHeightDp(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->screenHeightDp = out->SCREENWIDTH_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 'h') return false;
+    name++;
+    const char* x = name;
+    while (*x >= '0' && *x <= '9') x++;
+    if (x == name || x[0] != 'd' || x[1] != 'p' || x[2] != 0) return false;
+    std::string xName(name, x-name);
+
+    if (out) {
+        out->screenHeightDp = (uint16_t)atoi(xName.c_str());
+    }
+
+    return true;
+}
+
+static bool parseVersion(const char* name, ResTable_config* out) {
+    if (strcmp(name, kWildcardName) == 0) {
+        if (out) {
+            out->sdkVersion = out->SDKVERSION_ANY;
+            out->minorVersion = out->MINORVERSION_ANY;
+        }
+        return true;
+    }
+
+    if (*name != 'v') {
+        return false;
+    }
+
+    name++;
+    const char* s = name;
+    while (*s >= '0' && *s <= '9') s++;
+    if (s == name || *s != 0) return false;
+    std::string sdkName(name, s-name);
+
+    if (out) {
+        out->sdkVersion = (uint16_t)atoi(sdkName.c_str());
+        out->minorVersion = 0;
+    }
+
+    return true;
+}
+
+bool ConfigDescription::parse(const StringPiece& str, ConfigDescription* out) {
+    std::vector<std::string> parts = util::splitAndLowercase(str, '-');
+
+    ConfigDescription config;
+    ssize_t partsConsumed = 0;
+    LocaleValue locale;
+
+    const auto partsEnd = parts.end();
+    auto partIter = parts.begin();
+
+    if (str.size() == 0) {
+        goto success;
+    }
+
+    if (parseMcc(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseMnc(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    // Locale spans a few '-' separators, so we let it
+    // control the index.
+    partsConsumed = locale.initFromParts(partIter, partsEnd);
+    if (partsConsumed < 0) {
+        return false;
+    } else {
+        locale.writeTo(&config);
+        partIter += partsConsumed;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseLayoutDirection(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseSmallestScreenWidthDp(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseScreenWidthDp(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseScreenHeightDp(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseScreenLayoutSize(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseScreenLayoutLong(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseOrientation(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseUiModeType(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseUiModeNight(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseDensity(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseTouchscreen(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseKeysHidden(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseKeyboard(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseNavHidden(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseNavigation(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseScreenSize(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    if (parseVersion(partIter->c_str(), &config)) {
+        ++partIter;
+        if (partIter == partsEnd) {
+            goto success;
+        }
+    }
+
+    // Unrecognized.
+    return false;
+
+success:
+    if (out != NULL) {
+        applyVersionForCompatibility(&config);
+        *out = config;
+    }
+    return true;
+}
+
+void ConfigDescription::applyVersionForCompatibility(ConfigDescription* config) {
+    uint16_t minSdk = 0;
+    if (config->density == ResTable_config::DENSITY_ANY) {
+        minSdk = SDK_LOLLIPOP;
+    } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY
+            || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY
+            || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) {
+        minSdk = SDK_HONEYCOMB_MR2;
+    } else if ((config->uiMode & ResTable_config::MASK_UI_MODE_TYPE)
+                != ResTable_config::UI_MODE_TYPE_ANY
+            ||  (config->uiMode & ResTable_config::MASK_UI_MODE_NIGHT)
+                != ResTable_config::UI_MODE_NIGHT_ANY) {
+        minSdk = SDK_FROYO;
+    } else if ((config->screenLayout & ResTable_config::MASK_SCREENSIZE)
+                != ResTable_config::SCREENSIZE_ANY
+            ||  (config->screenLayout & ResTable_config::MASK_SCREENLONG)
+                != ResTable_config::SCREENLONG_ANY
+            || config->density != ResTable_config::DENSITY_DEFAULT) {
+        minSdk = SDK_DONUT;
+    }
+
+    if (minSdk > config->sdkVersion) {
+        config->sdkVersion = minSdk;
+    }
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
new file mode 100644
index 0000000..67b4b75
--- /dev/null
+++ b/tools/aapt2/ConfigDescription.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_CONFIG_DESCRIPTION_H
+#define AAPT_CONFIG_DESCRIPTION_H
+
+#include "StringPiece.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <ostream>
+
+namespace aapt {
+
+/*
+ * Subclass of ResTable_config that adds convenient
+ * initialization and comparison methods.
+ */
+struct ConfigDescription : public android::ResTable_config {
+    /*
+     * Parse a string of the form 'fr-sw600dp-land' and fill in the
+     * given ResTable_config with resulting configuration parameters.
+     *
+     * The resulting configuration has the appropriate sdkVersion defined
+     * for backwards compatibility.
+     */
+    static bool parse(const StringPiece& str, ConfigDescription* out = nullptr);
+
+    /**
+     * If the configuration uses an axis that was added after
+     * the original Android release, make sure the SDK version
+     * is set accordingly.
+     */
+    static void applyVersionForCompatibility(ConfigDescription* config);
+
+    ConfigDescription();
+    ConfigDescription(const android::ResTable_config& o);
+    ConfigDescription(const ConfigDescription& o);
+    ConfigDescription(ConfigDescription&& o);
+
+    ConfigDescription& operator=(const android::ResTable_config& o);
+    ConfigDescription& operator=(const ConfigDescription& o);
+    ConfigDescription& operator=(ConfigDescription&& o);
+
+    bool operator<(const ConfigDescription& o) const;
+    bool operator<=(const ConfigDescription& o) const;
+    bool operator==(const ConfigDescription& o) const;
+    bool operator!=(const ConfigDescription& o) const;
+    bool operator>=(const ConfigDescription& o) const;
+    bool operator>(const ConfigDescription& o) const;
+};
+
+inline ConfigDescription::ConfigDescription() {
+    memset(this, 0, sizeof(*this));
+    size = sizeof(android::ResTable_config);
+}
+
+inline ConfigDescription::ConfigDescription(const android::ResTable_config& o) {
+    *static_cast<android::ResTable_config*>(this) = o;
+    size = sizeof(android::ResTable_config);
+}
+
+inline ConfigDescription::ConfigDescription(const ConfigDescription& o) {
+    *static_cast<android::ResTable_config*>(this) = o;
+}
+
+inline ConfigDescription::ConfigDescription(ConfigDescription&& o) {
+    *this = o;
+}
+
+inline ConfigDescription& ConfigDescription::operator=(const android::ResTable_config& o) {
+    *static_cast<android::ResTable_config*>(this) = o;
+    size = sizeof(android::ResTable_config);
+    return *this;
+}
+
+inline ConfigDescription& ConfigDescription::operator=(const ConfigDescription& o) {
+    *static_cast<android::ResTable_config*>(this) = o;
+    return *this;
+}
+
+inline ConfigDescription& ConfigDescription::operator=(ConfigDescription&& o) {
+    *this = o;
+    return *this;
+}
+
+inline bool ConfigDescription::operator<(const ConfigDescription& o) const {
+    return compare(o) < 0;
+}
+
+inline bool ConfigDescription::operator<=(const ConfigDescription& o) const {
+    return compare(o) <= 0;
+}
+
+inline bool ConfigDescription::operator==(const ConfigDescription& o) const {
+    return compare(o) == 0;
+}
+
+inline bool ConfigDescription::operator!=(const ConfigDescription& o) const {
+    return compare(o) != 0;
+}
+
+inline bool ConfigDescription::operator>=(const ConfigDescription& o) const {
+    return compare(o) >= 0;
+}
+
+inline bool ConfigDescription::operator>(const ConfigDescription& o) const {
+    return compare(o) > 0;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const ConfigDescription& o) {
+    return out << o.toString().string();
+}
+
+} // namespace aapt
+
+#endif // AAPT_CONFIG_DESCRIPTION_H
diff --git a/tools/aapt2/ConfigDescription_test.cpp b/tools/aapt2/ConfigDescription_test.cpp
new file mode 100644
index 0000000..c57e351
--- /dev/null
+++ b/tools/aapt2/ConfigDescription_test.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigDescription.h"
+#include "StringPiece.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace aapt {
+
+static ::testing::AssertionResult TestParse(const StringPiece& input,
+                                            ConfigDescription* config = nullptr) {
+    if (ConfigDescription::parse(input, config)) {
+        return ::testing::AssertionSuccess() << input << " was successfully parsed";
+    }
+    return ::testing::AssertionFailure() << input << " could not be parsed";
+}
+
+TEST(ConfigDescriptionTest, ParseFailWhenQualifiersAreOutOfOrder) {
+    EXPECT_FALSE(TestParse("en-sw600dp-ldrtl"));
+    EXPECT_FALSE(TestParse("land-en"));
+    EXPECT_FALSE(TestParse("hdpi-320dpi"));
+}
+
+TEST(ConfigDescriptionTest, ParseFailWhenQualifiersAreNotMatched) {
+    EXPECT_FALSE(TestParse("en-sw600dp-ILLEGAL"));
+}
+
+TEST(ConfigDescriptionTest, ParseFailWhenQualifiersHaveTrailingDash) {
+    EXPECT_FALSE(TestParse("en-sw600dp-land-"));
+}
+
+TEST(ConfigDescriptionTest, ParseBasicQualifiers) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("", &config));
+    EXPECT_EQ(std::string(""), config.toString().string());
+
+    EXPECT_TRUE(TestParse("fr-land", &config));
+    EXPECT_EQ(std::string("fr-land"), config.toString().string());
+
+    EXPECT_TRUE(TestParse("mcc310-pl-sw720dp-normal-long-port-night-"
+                "xhdpi-keyssoft-qwerty-navexposed-nonav", &config));
+    EXPECT_EQ(std::string("mcc310-pl-sw720dp-normal-long-port-night-"
+                "xhdpi-keyssoft-qwerty-navexposed-nonav-v13"), config.toString().string());
+}
+
+TEST(ConfigDescriptionTest, ParseLocales) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("en-rUS", &config));
+    EXPECT_EQ(std::string("en-rUS"), config.toString().string());
+}
+
+TEST(ConfigDescriptionTest, ParseQualifierAddedInApi13) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("sw600dp", &config));
+    EXPECT_EQ(std::string("sw600dp-v13"), config.toString().string());
+
+    EXPECT_TRUE(TestParse("sw600dp-v8", &config));
+    EXPECT_EQ(std::string("sw600dp-v13"), config.toString().string());
+}
+
+TEST(ConfigDescriptionTest, ParseCarAttribute) {
+    ConfigDescription config;
+    EXPECT_TRUE(TestParse("car", &config));
+    EXPECT_EQ(android::ResTable_config::UI_MODE_TYPE_CAR, config.uiMode);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Files.cpp b/tools/aapt2/Files.cpp
new file mode 100644
index 0000000..8484148
--- /dev/null
+++ b/tools/aapt2/Files.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Files.h"
+#include "Util.h"
+
+#include <cerrno>
+#include <dirent.h>
+#include <string>
+#include <sys/stat.h>
+
+#ifdef HAVE_MS_C_RUNTIME
+// Windows includes.
+#include <direct.h>
+#endif
+
+namespace aapt {
+
+FileType getFileType(const StringPiece& path) {
+    struct stat sb;
+    if (stat(path.data(), &sb) < 0) {
+        if (errno == ENOENT || errno == ENOTDIR) {
+            return FileType::kNonexistant;
+        }
+        return FileType::kUnknown;
+    }
+
+    if (S_ISREG(sb.st_mode)) {
+        return FileType::kRegular;
+    } else if (S_ISDIR(sb.st_mode)) {
+        return FileType::kDirectory;
+    } else if (S_ISCHR(sb.st_mode)) {
+        return FileType::kCharDev;
+    } else if (S_ISBLK(sb.st_mode)) {
+        return FileType::kBlockDev;
+    } else if (S_ISFIFO(sb.st_mode)) {
+        return FileType::kFifo;
+#if defined(S_ISLNK)
+    } else if (S_ISLNK(sb.st_mode)) {
+        return FileType::kSymlink;
+#endif
+#if defined(S_ISSOCK)
+    } else if (S_ISSOCK(sb.st_mode)) {
+        return FileType::kSocket;
+#endif
+    } else {
+        return FileType::kUnknown;
+    }
+}
+
+std::vector<std::string> listFiles(const StringPiece& root) {
+    DIR* dir = opendir(root.data());
+    if (dir == nullptr) {
+        Logger::error(Source{ root.toString() })
+            << "unable to open file: "
+            << strerror(errno)
+            << "."
+            << std::endl;
+        return {};
+    }
+
+    std::vector<std::string> files;
+    dirent* entry;
+    while ((entry = readdir(dir))) {
+        files.emplace_back(entry->d_name);
+    }
+
+    closedir(dir);
+    return files;
+}
+
+inline static int mkdirImpl(const StringPiece& path) {
+#ifdef HAVE_MS_C_RUNTIME
+    return _mkdir(path.toString().c_str());
+#else
+    return mkdir(path.toString().c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
+#endif
+}
+
+bool mkdirs(const StringPiece& path) {
+    const char* start = path.begin();
+    const char* end = path.end();
+    for (const char* current = start; current != end; ++current) {
+        if (*current == sDirSep) {
+            StringPiece parentPath(start, current - start);
+            int result = mkdirImpl(parentPath);
+            if (result < 0 && errno != EEXIST) {
+                return false;
+            }
+        }
+    }
+    return mkdirImpl(path) == 0 || errno == EEXIST;
+}
+
+std::string getStem(const StringPiece& path) {
+    const char* start = path.begin();
+    const char* end = path.end();
+    for (const char* current = end - 1; current != start - 1; --current) {
+        if (*current == sDirSep) {
+            return std::string(start, current - start);
+        }
+    }
+    return {};
+}
+
+bool FileFilter::setPattern(const StringPiece& pattern) {
+    mPatternTokens = util::splitAndLowercase(pattern, ':');
+    return true;
+}
+
+bool FileFilter::operator()(const std::string& filename, FileType type) const {
+    if (filename == "." || filename == "..") {
+        return false;
+    }
+
+    const char kDir[] = "dir";
+    const char kFile[] = "file";
+    const size_t filenameLen = filename.length();
+    bool chatty = true;
+    for (const std::string& token : mPatternTokens) {
+        const char* tokenStr = token.c_str();
+        if (*tokenStr == '!') {
+            chatty = false;
+            tokenStr++;
+        }
+
+        if (strncasecmp(tokenStr, kDir, sizeof(kDir)) == 0) {
+            if (type != FileType::kDirectory) {
+                continue;
+            }
+            tokenStr += sizeof(kDir);
+        }
+
+        if (strncasecmp(tokenStr, kFile, sizeof(kFile)) == 0) {
+            if (type != FileType::kRegular) {
+                continue;
+            }
+            tokenStr += sizeof(kFile);
+        }
+
+        bool ignore = false;
+        size_t n = strlen(tokenStr);
+        if (*tokenStr == '*') {
+            // Math suffix.
+            tokenStr++;
+            n--;
+            if (n <= filenameLen) {
+                ignore = strncasecmp(tokenStr, filename.c_str() + filenameLen - n, n) == 0;
+            }
+        } else if (n > 1 && tokenStr[n - 1] == '*') {
+            // Match prefix.
+            ignore = strncasecmp(tokenStr, filename.c_str(), n - 1) == 0;
+        } else {
+            ignore = strcasecmp(tokenStr, filename.c_str()) == 0;
+        }
+
+        if (ignore) {
+            if (chatty) {
+                Logger::warn()
+                    << "skipping " <<
+                    (type == FileType::kDirectory ? "dir '" : "file '")
+                    << filename
+                    << "' due to ignore pattern '"
+                    << token
+                    << "'."
+                    << std::endl;
+            }
+            return false;
+        }
+    }
+    return true;
+}
+
+
+} // namespace aapt
diff --git a/tools/aapt2/Files.h b/tools/aapt2/Files.h
new file mode 100644
index 0000000..844fd2b
--- /dev/null
+++ b/tools/aapt2/Files.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_FILES_H
+#define AAPT_FILES_H
+
+#include "Logger.h"
+#include "Source.h"
+#include "StringPiece.h"
+
+#include <cassert>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+#ifdef _WIN32
+constexpr const char sDirSep = '\\';
+#else
+constexpr const char sDirSep = '/';
+#endif
+
+enum class FileType {
+    kUnknown = 0,
+    kNonexistant,
+    kRegular,
+    kDirectory,
+    kCharDev,
+    kBlockDev,
+    kFifo,
+    kSymlink,
+    kSocket,
+};
+
+FileType getFileType(const StringPiece& path);
+
+/*
+ * Lists files under the directory `root`. Files are listed
+ * with just their leaf (filename) names.
+ */
+std::vector<std::string> listFiles(const StringPiece& root);
+
+/*
+ * Appends a path to `base`, separated by the directory separator.
+ */
+void appendPath(std::string* base, const StringPiece& part);
+
+/*
+ * Appends a series of paths to `base`, separated by the
+ * system directory separator.
+ */
+template <typename... Ts >
+void appendPath(std::string* base, const StringPiece& part, const Ts&... parts);
+
+/*
+ * Makes all the directories in `path`. The last element in the path
+ * is interpreted as a directory.
+ */
+bool mkdirs(const StringPiece& path);
+
+/**
+ * Returns all but the last part of the path.
+ */
+std::string getStem(const StringPiece& path);
+
+/*
+ * Filter that determines which resource files/directories are
+ * processed by AAPT. Takes a pattern string supplied by the user.
+ * Pattern format is specified in the
+ * FileFilter::setPattern(const std::string&) method.
+ */
+class FileFilter {
+public:
+    /*
+     * Patterns syntax:
+     * - Delimiter is :
+     * - Entry can start with the flag ! to avoid printing a warning
+     *   about the file being ignored.
+     * - Entry can have the flag "<dir>" to match only directories
+     *   or <file> to match only files. Default is to match both.
+     * - Entry can be a simplified glob "<prefix>*" or "*<suffix>"
+     *   where prefix/suffix must have at least 1 character (so that
+     *   we don't match a '*' catch-all pattern.)
+     * - The special filenames "." and ".." are always ignored.
+     * - Otherwise the full string is matched.
+     * - match is not case-sensitive.
+     */
+    bool setPattern(const StringPiece& pattern);
+
+    /**
+     * Applies the filter, returning true for pass, false for fail.
+     */
+    bool operator()(const std::string& filename, FileType type) const;
+
+private:
+    std::vector<std::string> mPatternTokens;
+};
+
+inline void appendPath(std::string* base, const StringPiece& part) {
+    assert(base);
+    *base += sDirSep;
+    base->append(part.data(), part.size());
+}
+
+template <typename... Ts >
+void appendPath(std::string* base, const StringPiece& part, const Ts&... parts) {
+    assert(base);
+    *base += sDirSep;
+    base->append(part.data(), part.size());
+    appendPath(base, parts...);
+}
+
+} // namespace aapt
+
+#endif // AAPT_FILES_H
diff --git a/tools/aapt2/Flag.cpp b/tools/aapt2/Flag.cpp
new file mode 100644
index 0000000..b1ee8e7
--- /dev/null
+++ b/tools/aapt2/Flag.cpp
@@ -0,0 +1,109 @@
+#include "Flag.h"
+#include "StringPiece.h"
+
+#include <functional>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+namespace flag {
+
+struct Flag {
+    std::string name;
+    std::string description;
+    std::function<void(const StringPiece&)> action;
+    bool required;
+    bool* flagResult;
+    bool parsed;
+};
+
+static std::vector<Flag> sFlags;
+static std::vector<std::string> sArgs;
+
+void optionalFlag(const StringPiece& name, const StringPiece& description,
+                  std::function<void(const StringPiece&)> action) {
+    sFlags.push_back(
+            Flag{ name.toString(), description.toString(), action, false, nullptr, false });
+}
+
+void requiredFlag(const StringPiece& name, const StringPiece& description,
+                  std::function<void(const StringPiece&)> action) {
+    sFlags.push_back(
+            Flag{ name.toString(), description.toString(), action, true, nullptr, false });
+}
+
+void optionalSwitch(const StringPiece& name, const StringPiece& description, bool* result) {
+    sFlags.push_back(
+            Flag{ name.toString(), description.toString(), {}, false, result, false });
+}
+
+static void usageAndDie(const StringPiece& command) {
+    std::cerr << command << " [options]";
+    for (const Flag& flag : sFlags) {
+        if (flag.required) {
+            std::cerr << " " << flag.name << " arg";
+        }
+    }
+    std::cerr << " files..." << std::endl << std::endl << "Options:" << std::endl;
+
+    for (const Flag& flag : sFlags) {
+        std::string command = flag.name;
+        if (!flag.flagResult) {
+            command += " arg ";
+        }
+        std::cerr << "  " << std::setw(30) << std::left << command
+                  << flag.description << std::endl;
+    }
+    exit(1);
+}
+
+void parse(int argc, char** argv, const StringPiece& command) {
+    for (int i = 0; i < argc; i++) {
+        const StringPiece arg(argv[i]);
+        if (*arg.data() != '-') {
+            sArgs.emplace_back(arg.toString());
+            continue;
+        }
+
+        bool match = false;
+        for (Flag& flag : sFlags) {
+            if (arg == flag.name) {
+                match = true;
+                flag.parsed = true;
+                if (flag.flagResult) {
+                    *flag.flagResult = true;
+                } else {
+                    i++;
+                    if (i >= argc) {
+                        std::cerr << flag.name << " missing argument." << std::endl
+                                  << std::endl;
+                        usageAndDie(command);
+                    }
+                    flag.action(argv[i]);
+                }
+                break;
+            }
+        }
+
+        if (!match) {
+            std::cerr << "unknown option '" << arg << "'." << std::endl << std::endl;
+            usageAndDie(command);
+        }
+    }
+
+    for (const Flag& flag : sFlags) {
+        if (flag.required && !flag.parsed) {
+            std::cerr << "missing required flag " << flag.name << std::endl << std::endl;
+            usageAndDie(command);
+        }
+    }
+}
+
+const std::vector<std::string>& getArgs() {
+    return sArgs;
+}
+
+} // namespace flag
+} // namespace aapt
diff --git a/tools/aapt2/Flag.h b/tools/aapt2/Flag.h
new file mode 100644
index 0000000..32f5f2c
--- /dev/null
+++ b/tools/aapt2/Flag.h
@@ -0,0 +1,28 @@
+#ifndef AAPT_FLAG_H
+#define AAPT_FLAG_H
+
+#include "StringPiece.h"
+
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace aapt {
+namespace flag {
+
+void requiredFlag(const StringPiece& name, const StringPiece& description,
+                  std::function<void(const StringPiece&)> action);
+
+void optionalFlag(const StringPiece& name, const StringPiece& description,
+                  std::function<void(const StringPiece&)> action);
+
+void optionalSwitch(const StringPiece& name, const StringPiece& description, bool* result);
+
+void parse(int argc, char** argv, const StringPiece& command);
+
+const std::vector<std::string>& getArgs();
+
+} // namespace flag
+} // namespace aapt
+
+#endif // AAPT_FLAG_H
diff --git a/tools/aapt2/JavaClassGenerator.cpp b/tools/aapt2/JavaClassGenerator.cpp
new file mode 100644
index 0000000..779a346
--- /dev/null
+++ b/tools/aapt2/JavaClassGenerator.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JavaClassGenerator.h"
+#include "Resource.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "StringPiece.h"
+
+#include <algorithm>
+#include <ostream>
+#include <set>
+#include <sstream>
+#include <tuple>
+
+namespace aapt {
+
+// The number of attributes to emit per line in a Styleable array.
+constexpr size_t kAttribsPerLine = 4;
+
+JavaClassGenerator::JavaClassGenerator(std::shared_ptr<const ResourceTable> table,
+                                       Options options) :
+        mTable(table), mOptions(options) {
+}
+
+static void generateHeader(std::ostream& out, const StringPiece16& package) {
+    out << "/* AUTO-GENERATED FILE. DO NOT MODIFY.\n"
+           " *\n"
+           " * This class was automatically generated by the\n"
+           " * aapt tool from the resource data it found. It\n"
+           " * should not be modified by hand.\n"
+           " */\n\n";
+    out << "package " << package << ";"
+        << std::endl
+        << std::endl;
+}
+
+static const std::set<StringPiece16> sJavaIdentifiers = {
+    u"abstract", u"assert", u"boolean", u"break", u"byte",
+    u"case", u"catch", u"char", u"class", u"const", u"continue",
+    u"default", u"do", u"double", u"else", u"enum", u"extends",
+    u"final", u"finally", u"float", u"for", u"goto", u"if",
+    u"implements", u"import", u"instanceof", u"int", u"interface",
+    u"long", u"native", u"new", u"package", u"private", u"protected",
+    u"public", u"return", u"short", u"static", u"strictfp", u"super",
+    u"switch", u"synchronized", u"this", u"throw", u"throws",
+    u"transient", u"try", u"void", u"volatile", u"while", u"true",
+    u"false", u"null"
+};
+
+static bool isValidSymbol(const StringPiece16& symbol) {
+    return sJavaIdentifiers.find(symbol) == sJavaIdentifiers.end();
+}
+
+/*
+ * Java symbols can not contain . or -, but those are valid in a resource name.
+ * Replace those with '_'.
+ */
+static std::u16string transform(const StringPiece16& symbol) {
+    std::u16string output = symbol.toString();
+    for (char16_t& c : output) {
+        if (c == u'.' || c == u'-') {
+            c = u'_';
+        }
+    }
+    return output;
+}
+
+bool JavaClassGenerator::generateType(std::ostream& out, const ResourceTableType& type,
+                                      size_t packageId) {
+    const StringPiece finalModifier = mOptions.useFinal ? " final" : "";
+
+    for (const auto& entry : type.entries) {
+        ResourceId id = { packageId, type.typeId, entry->entryId };
+        assert(id.isValid());
+
+        if (!isValidSymbol(entry->name)) {
+            std::stringstream err;
+            err << "invalid symbol name '"
+                << StringPiece16(entry->name)
+                << "'";
+            mError = err.str();
+            return false;
+        }
+
+        out << "        "
+            << "public static" << finalModifier
+            << " int " << transform(entry->name) << " = " << id << ";" << std::endl;
+    }
+    return true;
+}
+
+struct GenArgs : ValueVisitorArgs {
+    GenArgs(std::ostream& o, const ResourceEntry& e) : out(o), entry(e) {
+    }
+
+    std::ostream& out;
+    const ResourceEntry& entry;
+};
+
+void JavaClassGenerator::visit(const Styleable& styleable, ValueVisitorArgs& a) {
+    const StringPiece finalModifier = mOptions.useFinal ? " final" : "";
+    std::ostream& out = static_cast<GenArgs&>(a).out;
+    const ResourceEntry& entry = static_cast<GenArgs&>(a).entry;
+
+    // This must be sorted by resource ID.
+    std::vector<std::pair<ResourceId, StringPiece16>> sortedAttributes;
+    sortedAttributes.reserve(styleable.entries.size());
+    for (const auto& attr : styleable.entries) {
+        assert(attr.id.isValid() && "no ID set for Styleable entry");
+        assert(attr.name.isValid() && "no name set for Styleable entry");
+        sortedAttributes.emplace_back(attr.id, attr.name.entry);
+    }
+    std::sort(sortedAttributes.begin(), sortedAttributes.end());
+
+    // First we emit the array containing the IDs of each attribute.
+    out << "        "
+        << "public static final int[] " << transform(entry.name) << " = {";
+
+    const size_t attrCount = sortedAttributes.size();
+    for (size_t i = 0; i < attrCount; i++) {
+        if (i % kAttribsPerLine == 0) {
+            out << std::endl << "            ";
+        }
+
+        out << sortedAttributes[i].first;
+        if (i != attrCount - 1) {
+            out << ", ";
+        }
+    }
+    out << std::endl << "        };" << std::endl;
+
+    // Now we emit the indices into the array.
+    for (size_t i = 0; i < attrCount; i++) {
+        out << "        "
+            << "public static" << finalModifier
+            << " int " << transform(entry.name) << "_" << transform(sortedAttributes[i].second)
+            << " = " << i << ";" << std::endl;
+    }
+}
+
+bool JavaClassGenerator::generate(std::ostream& out) {
+    const size_t packageId = mTable->getPackageId();
+
+    generateHeader(out, mTable->getPackage());
+
+    out << "public final class R {" << std::endl;
+
+    for (const auto& type : *mTable) {
+        out << "    public static final class " << type->type << " {" << std::endl;
+        bool result;
+        if (type->type == ResourceType::kStyleable) {
+            for (const auto& entry : type->entries) {
+                assert(!entry->values.empty());
+                if (!isValidSymbol(entry->name)) {
+                    std::stringstream err;
+                    err << "invalid symbol name '"
+                        << StringPiece16(entry->name)
+                        << "'";
+                    mError = err.str();
+                    return false;
+                }
+                entry->values.front().value->accept(*this, GenArgs{ out, *entry });
+            }
+        } else {
+            result = generateType(out, *type, packageId);
+        }
+
+        if (!result) {
+            return false;
+        }
+        out << "    }" << std::endl;
+    }
+
+    out << "}" << std::endl;
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/JavaClassGenerator.h b/tools/aapt2/JavaClassGenerator.h
new file mode 100644
index 0000000..5b8e500
--- /dev/null
+++ b/tools/aapt2/JavaClassGenerator.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_JAVA_CLASS_GENERATOR_H
+#define AAPT_JAVA_CLASS_GENERATOR_H
+
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+
+#include <ostream>
+#include <string>
+
+namespace aapt {
+
+/*
+ * Generates the R.java file for a resource table.
+ */
+class JavaClassGenerator : ConstValueVisitor {
+public:
+    /*
+     * A set of options for this JavaClassGenerator.
+     */
+    struct Options {
+        /*
+         * Specifies whether to use the 'final' modifier
+         * on resource entries. Default is true.
+         */
+        bool useFinal = true;
+    };
+
+    JavaClassGenerator(std::shared_ptr<const ResourceTable> table, Options options);
+
+    /*
+     * Writes the R.java file to `out`. Returns true on success.
+     */
+    bool generate(std::ostream& out);
+
+    /*
+     * ConstValueVisitor implementation.
+     */
+    void visit(const Styleable& styleable, ValueVisitorArgs& args);
+
+    const std::string& getError() const;
+
+private:
+    bool generateType(std::ostream& out, const ResourceTableType& type, size_t packageId);
+
+    std::shared_ptr<const ResourceTable> mTable;
+    Options mOptions;
+    std::string mError;
+};
+
+inline const std::string& JavaClassGenerator::getError() const {
+    return mError;
+}
+
+} // namespace aapt
+
+#endif // AAPT_JAVA_CLASS_GENERATOR_H
diff --git a/tools/aapt2/JavaClassGenerator_test.cpp b/tools/aapt2/JavaClassGenerator_test.cpp
new file mode 100644
index 0000000..32050e3
--- /dev/null
+++ b/tools/aapt2/JavaClassGenerator_test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JavaClassGenerator.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+struct JavaClassGeneratorTest : public ::testing::Test {
+    virtual void SetUp() override {
+        mTable = std::make_shared<ResourceTable>();
+        mTable->setPackage(u"android");
+        mTable->setPackageId(0x01);
+    }
+
+    bool addResource(const ResourceNameRef& name, ResourceId id) {
+        return mTable->addResource(name, id, {}, SourceLine{ "test.xml", 21 },
+                                   util::make_unique<Id>());
+    }
+
+    std::shared_ptr<ResourceTable> mTable;
+};
+
+TEST_F(JavaClassGeneratorTest, FailWhenEntryIsJavaKeyword) {
+    ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"class" },
+                            ResourceId{ 0x01, 0x02, 0x0000 }));
+
+    JavaClassGenerator generator(mTable, {});
+
+    std::stringstream out;
+    EXPECT_FALSE(generator.generate(out));
+}
+
+TEST_F(JavaClassGeneratorTest, TransformInvalidJavaIdentifierCharacter) {
+    ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kId, u"hey-man" },
+                            ResourceId{ 0x01, 0x02, 0x0000 }));
+
+    ASSERT_TRUE(addResource(ResourceName{ {}, ResourceType::kAttr, u"cool.attr" },
+                            ResourceId{ 0x01, 0x01, 0x0000 }));
+
+    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+    Reference ref(ResourceName{ u"android", ResourceType::kAttr, u"cool.attr"});
+    ref.id = ResourceId{ 0x01, 0x01, 0x0000 };
+    styleable->entries.emplace_back(ref);
+
+    ASSERT_TRUE(mTable->addResource(ResourceName{ {}, ResourceType::kStyleable, u"hey.dude" },
+                                    ResourceId{ 0x01, 0x03, 0x0000 }, {},
+                                    SourceLine{ "test.xml", 21 }, std::move(styleable)));
+
+    JavaClassGenerator generator(mTable, {});
+
+    std::stringstream out;
+    EXPECT_TRUE(generator.generate(out));
+    std::string output = out.str();
+
+    EXPECT_NE(std::string::npos,
+              output.find("public static final int hey_man = 0x01020000;"));
+
+    EXPECT_NE(std::string::npos,
+              output.find("public static final int[] hey_dude = {"));
+
+    EXPECT_NE(std::string::npos,
+              output.find("public static final int hey_dude_cool_attr = 0;"));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Linker.cpp b/tools/aapt2/Linker.cpp
new file mode 100644
index 0000000..1cfb297
--- /dev/null
+++ b/tools/aapt2/Linker.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Linker.h"
+#include "Logger.h"
+#include "ResourceParser.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "StringPiece.h"
+#include "Util.h"
+
+#include <androidfw/AssetManager.h>
+#include <array>
+#include <bitset>
+#include <iostream>
+#include <map>
+#include <ostream>
+#include <set>
+#include <sstream>
+#include <tuple>
+#include <vector>
+
+namespace aapt {
+
+Linker::Args::Args(const ResourceNameRef& r, const SourceLine& s) : referrer(r), source(s) {
+}
+
+Linker::Linker(std::shared_ptr<ResourceTable> table, std::shared_ptr<Resolver> resolver) :
+        mTable(table), mResolver(resolver), mError(false) {
+}
+
+bool Linker::linkAndValidate() {
+    std::bitset<256> usedTypeIds;
+    std::array<std::set<uint16_t>, 256> usedIds;
+    usedTypeIds.set(0);
+
+    // First build the graph of references.
+    for (auto& type : *mTable) {
+        if (type->typeId != ResourceTableType::kUnsetTypeId) {
+            // The ID for this type has already been set. We
+            // mark this ID as taken so we don't re-assign it
+            // later.
+            usedTypeIds.set(type->typeId);
+        }
+
+        for (auto& entry : type->entries) {
+            if (type->typeId != ResourceTableType::kUnsetTypeId &&
+                    entry->entryId != ResourceEntry::kUnsetEntryId) {
+                // The ID for this entry has already been set. We
+                // mark this ID as taken so we don't re-assign it
+                // later.
+                usedIds[type->typeId].insert(entry->entryId);
+            }
+
+            for (auto& valueConfig : entry->values) {
+                // Dispatch to the right method of this linker
+                // based on the value's type.
+                valueConfig.value->accept(*this, Args{
+                        ResourceNameRef{ mTable->getPackage(), type->type, entry->name },
+                        valueConfig.source
+                });
+            }
+        }
+    }
+
+    /*
+     * Assign resource IDs that are available.
+     */
+    size_t nextTypeIndex = 0;
+    for (auto& type : *mTable) {
+        if (type->typeId == ResourceTableType::kUnsetTypeId) {
+            while (nextTypeIndex < usedTypeIds.size() && usedTypeIds[nextTypeIndex]) {
+                nextTypeIndex++;
+            }
+            type->typeId = nextTypeIndex++;
+        }
+
+        const auto endEntryIter = std::end(usedIds[type->typeId]);
+        auto nextEntryIter = std::begin(usedIds[type->typeId]);
+        size_t nextIndex = 0;
+        for (auto& entry : type->entries) {
+            if (entry->entryId == ResourceTableType::kUnsetTypeId) {
+                while (nextEntryIter != endEntryIter &&
+                        nextIndex == *nextEntryIter) {
+                    nextIndex++;
+                    ++nextEntryIter;
+                }
+                entry->entryId = nextIndex++;
+
+                // Update callers of this resource with the right ID.
+                auto callersIter = mGraph.find(ResourceNameRef{
+                        mTable->getPackage(),
+                        type->type,
+                        entry->name
+                });
+
+                if (callersIter != std::end(mGraph)) {
+                    for (Node& caller : callersIter->second) {
+                        caller.reference->id = ResourceId(mTable->getPackageId(),
+                                                          type->typeId,
+                                                          entry->entryId);
+                    }
+                }
+            }
+        }
+    }
+
+    return !mError;
+}
+
+const Linker::ResourceNameToSourceMap& Linker::getUnresolvedReferences() const {
+    return mUnresolvedSymbols;
+}
+
+void Linker::visit(Reference& reference, ValueVisitorArgs& a) {
+    Args& args = static_cast<Args&>(a);
+
+    Maybe<ResourceId> result = mResolver->findId(reference.name);
+    if (!result) {
+        addUnresolvedSymbol(reference.name, args.source);
+        return;
+    }
+
+    const ResourceId& id = result.value();
+    if (id.isValid()) {
+        reference.id = id;
+    } else {
+        // We need to update the ID when it is set, so add it
+        // to the graph.
+        mGraph[reference.name].push_back(Node{
+                args.referrer,
+                args.source.path,
+                args.source.line,
+                &reference
+        });
+    }
+
+    // TODO(adamlesinski): Verify the referencedType is another reference
+    // or a compatible primitive.
+}
+
+void Linker::processAttributeValue(const ResourceNameRef& name, const SourceLine& source,
+        const Attribute& attr, std::unique_ptr<Item>& value) {
+    std::unique_ptr<Item> convertedValue;
+    visitFunc<RawString>(*value, [&](RawString& str) {
+        // This is a raw string, so check if it can be converted to anything.
+        // We can NOT swap value with the converted value in here, since
+        // we called through the original value.
+
+        auto onCreateReference = [&](const ResourceName& name) {
+            mTable->addResource(name, ConfigDescription{},
+                    source, util::make_unique<Id>());
+        };
+
+        convertedValue = ResourceParser::parseItemForAttribute(
+                *str.value, attr, mResolver->getDefaultPackage(),
+                onCreateReference);
+        if (!convertedValue && attr.typeMask & android::ResTable_map::TYPE_STRING) {
+            // Last effort is to parse as a string.
+            util::StringBuilder builder;
+            builder.append(*str.value);
+            if (builder) {
+                convertedValue = util::make_unique<String>(
+                        mTable->getValueStringPool().makeRef(builder.str()));
+            }
+        }
+    });
+
+    if (convertedValue) {
+        value = std::move(convertedValue);
+    }
+
+    // Process this new or old value (it can be a reference!).
+    value->accept(*this, Args{ name, source });
+
+    // Flatten the value to see what resource type it is.
+    android::Res_value resValue;
+    value->flatten(resValue);
+
+    // Always allow references.
+    const uint32_t typeMask = attr.typeMask | android::ResTable_map::TYPE_REFERENCE;
+    if (!(typeMask & ResourceParser::androidTypeToAttributeTypeMask(resValue.dataType))) {
+        Logger::error(source)
+                << *value
+                << " is not compatible with attribute "
+                << attr
+                << "."
+                << std::endl;
+        mError = true;
+    }
+}
+
+void Linker::visit(Style& style, ValueVisitorArgs& a) {
+    Args& args = static_cast<Args&>(a);
+
+    if (style.parent.name.isValid()) {
+        visit(style.parent, a);
+    }
+
+    for (Style::Entry& styleEntry : style.entries) {
+        Maybe<Resolver::Entry> result = mResolver->findAttribute(styleEntry.key.name);
+        if (!result || !result.value().attr) {
+            addUnresolvedSymbol(styleEntry.key.name, args.source);
+            continue;
+        }
+
+        const Resolver::Entry& entry = result.value();
+        if (entry.id.isValid()) {
+            styleEntry.key.id = entry.id;
+        } else {
+            // Create a dependency for the style on this attribute.
+            mGraph[styleEntry.key.name].push_back(Node{
+                    args.referrer,
+                    args.source.path,
+                    args.source.line,
+                    &styleEntry.key
+            });
+        }
+        processAttributeValue(args.referrer, args.source, *entry.attr, styleEntry.value);
+    }
+}
+
+void Linker::visit(Attribute& attr, ValueVisitorArgs& a) {
+    static constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM |
+            android::ResTable_map::TYPE_FLAGS;
+    if (attr.typeMask & kMask) {
+        for (auto& symbol : attr.symbols) {
+            visit(symbol.symbol, a);
+        }
+    }
+}
+
+void Linker::visit(Styleable& styleable, ValueVisitorArgs& a) {
+    for (auto& attrRef : styleable.entries) {
+        visit(attrRef, a);
+    }
+}
+
+void Linker::visit(Sentinel& sentinel, ValueVisitorArgs& a) {
+    Args& args = static_cast<Args&>(a);
+    addUnresolvedSymbol(args.referrer, args.source);
+}
+
+void Linker::visit(Array& array, ValueVisitorArgs& a) {
+    Args& args = static_cast<Args&>(a);
+
+    for (auto& item : array.items) {
+        item->accept(*this, Args{ args.referrer, args.source });
+    }
+}
+
+void Linker::visit(Plural& plural, ValueVisitorArgs& a) {
+    Args& args = static_cast<Args&>(a);
+
+    for (auto& item : plural.values) {
+        if (item) {
+            item->accept(*this, Args{ args.referrer, args.source });
+        }
+    }
+}
+
+void Linker::addUnresolvedSymbol(const ResourceNameRef& name, const SourceLine& source) {
+    mUnresolvedSymbols[name.toResourceName()].push_back(source);
+}
+
+::std::ostream& operator<<(::std::ostream& out, const Linker::Node& node) {
+    return out << node.name << "(" << node.source << ":" << node.line << ")";
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Linker.h b/tools/aapt2/Linker.h
new file mode 100644
index 0000000..9b911b7
--- /dev/null
+++ b/tools/aapt2/Linker.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_LINKER_H
+#define AAPT_LINKER_H
+
+#include "Resolver.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Source.h"
+#include "StringPiece.h"
+
+#include <androidfw/AssetManager.h>
+#include <map>
+#include <memory>
+#include <ostream>
+#include <set>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * The Linker has two jobs. It follows resource references
+ * and verifies that their targert exists and that their
+ * types are compatible. The Linker will also assign resource
+ * IDs and fill in all the dependent references with the newly
+ * assigned resource IDs.
+ *
+ * To do this, the Linker builds a graph of references. This
+ * can be useful to do other analysis, like building a
+ * dependency graph of source files. The hope is to be able to
+ * add functionality that operates on the graph without
+ * overcomplicating the Linker.
+ *
+ * TODO(adamlesinski): Build the graph first then run the separate
+ * steps over the graph.
+ */
+class Linker : ValueVisitor {
+public:
+    /**
+     * Create a Linker for the given resource table with the sources available in
+     * Resolver. Resolver should contain the ResourceTable as a source too.
+     */
+    Linker(std::shared_ptr<ResourceTable> table, std::shared_ptr<Resolver> resolver);
+
+    Linker(const Linker&) = delete;
+
+    /**
+     * Entry point to the linker. Assigns resource IDs, follows references,
+     * and validates types. Returns true if all references to defined values
+     * are type-compatible. Missing resource references are recorded but do
+     * not cause this method to fail.
+     */
+    bool linkAndValidate();
+
+    /**
+     * Returns any references to resources that were not defined in any of the
+     * sources.
+     */
+    using ResourceNameToSourceMap = std::map<ResourceName, std::vector<SourceLine>>;
+    const ResourceNameToSourceMap& getUnresolvedReferences() const;
+
+private:
+    struct Args : public ValueVisitorArgs {
+        Args(const ResourceNameRef& r, const SourceLine& s);
+
+        const ResourceNameRef& referrer;
+        const SourceLine& source;
+    };
+
+    //
+    // Overrides of ValueVisitor
+    //
+    void visit(Reference& reference, ValueVisitorArgs& args) override;
+    void visit(Attribute& attribute, ValueVisitorArgs& args) override;
+    void visit(Styleable& styleable, ValueVisitorArgs& args) override;
+    void visit(Style& style, ValueVisitorArgs& args) override;
+    void visit(Sentinel& sentinel, ValueVisitorArgs& args) override;
+    void visit(Array& array, ValueVisitorArgs& args) override;
+    void visit(Plural& plural, ValueVisitorArgs& args) override;
+
+    void processAttributeValue(const ResourceNameRef& name, const SourceLine& source,
+            const Attribute& attr, std::unique_ptr<Item>& value);
+
+    void addUnresolvedSymbol(const ResourceNameRef& name, const SourceLine& source);
+
+    /**
+     * Node of the resource table graph.
+     */
+    struct Node {
+        // We use ResourceNameRef and StringPiece, which are safe so long as the ResourceTable
+        // that defines the data isn't modified.
+        ResourceNameRef name;
+        StringPiece source;
+        size_t line;
+
+        // The reference object that points to name.
+        Reference* reference;
+
+        bool operator<(const Node& rhs) const;
+        bool operator==(const Node& rhs) const;
+        bool operator!=(const Node& rhs) const;
+    };
+    friend ::std::ostream& operator<<(::std::ostream&, const Node&);
+
+    std::shared_ptr<ResourceTable> mTable;
+    std::shared_ptr<Resolver> mResolver;
+    std::map<ResourceNameRef, std::vector<Node>> mGraph;
+    std::map<ResourceName, std::vector<SourceLine>> mUnresolvedSymbols;
+    bool mError;
+};
+
+} // namespace aapt
+
+#endif // AAPT_LINKER_H
diff --git a/tools/aapt2/Linker_test.cpp b/tools/aapt2/Linker_test.cpp
new file mode 100644
index 0000000..b1e201b
--- /dev/null
+++ b/tools/aapt2/Linker_test.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Linker.h"
+#include "Resolver.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <androidfw/AssetManager.h>
+#include <gtest/gtest.h>
+#include <string>
+
+namespace aapt {
+
+struct LinkerTest : public ::testing::Test {
+    virtual void SetUp() override {
+        mTable = std::make_shared<ResourceTable>();
+        mTable->setPackage(u"android");
+        mLinker = std::make_shared<Linker>(mTable, std::make_shared<Resolver>(
+                mTable, std::make_shared<android::AssetManager>()));
+
+        // Create a few attributes for use in the tests.
+
+        addResource(ResourceName{ {}, ResourceType::kAttr, u"integer" },
+                    util::make_unique<Attribute>(false, android::ResTable_map::TYPE_INTEGER));
+
+        addResource(ResourceName{ {}, ResourceType::kAttr, u"string" },
+                    util::make_unique<Attribute>(false, android::ResTable_map::TYPE_STRING));
+
+        addResource(ResourceName{ {}, ResourceType::kId, u"apple" }, util::make_unique<Id>());
+
+        addResource(ResourceName{ {}, ResourceType::kId, u"banana" }, util::make_unique<Id>());
+
+        std::unique_ptr<Attribute> flagAttr = util::make_unique<Attribute>(
+                false, android::ResTable_map::TYPE_FLAGS);
+        flagAttr->symbols.push_back(Attribute::Symbol{
+                ResourceNameRef{ u"android", ResourceType::kId, u"apple" }, 1 });
+        flagAttr->symbols.push_back(Attribute::Symbol{
+                ResourceNameRef{ u"android", ResourceType::kId, u"banana" }, 2 });
+        addResource(ResourceName{ {}, ResourceType::kAttr, u"flags" }, std::move(flagAttr));
+    }
+
+    /*
+     * Convenience method for adding resources with the default configuration and some
+     * bogus source line.
+     */
+    bool addResource(const ResourceNameRef& name, std::unique_ptr<Value> value) {
+        return mTable->addResource(name, {}, SourceLine{ "test.xml", 21 }, std::move(value));
+    }
+
+    std::shared_ptr<ResourceTable> mTable;
+    std::shared_ptr<Linker> mLinker;
+};
+
+TEST_F(LinkerTest, DoNotInterpretEscapedStringAsReference) {
+    ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kString, u"foo" },
+                util::make_unique<String>(mTable->getValueStringPool().makeRef(u"?123"))));
+
+    ASSERT_TRUE(mLinker->linkAndValidate());
+    EXPECT_TRUE(mLinker->getUnresolvedReferences().empty());
+}
+
+TEST_F(LinkerTest, EscapeAndConvertRawString) {
+    std::unique_ptr<Style> style = util::make_unique<Style>();
+    style->entries.push_back(Style::Entry{
+            ResourceNameRef{ u"android", ResourceType::kAttr, u"integer" },
+            util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"  123"))
+    });
+    const Style* result = style.get();
+    ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" },
+                std::move(style)));
+
+    ASSERT_TRUE(mLinker->linkAndValidate());
+    EXPECT_TRUE(mLinker->getUnresolvedReferences().empty());
+
+    EXPECT_NE(nullptr, dynamic_cast<BinaryPrimitive*>(result->entries.front().value.get()));
+}
+
+TEST_F(LinkerTest, FailToConvertRawString) {
+    std::unique_ptr<Style> style = util::make_unique<Style>();
+    style->entries.push_back(Style::Entry{
+            ResourceNameRef{ u"android", ResourceType::kAttr, u"integer" },
+            util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"yo what is up?"))
+    });
+    ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" },
+                std::move(style)));
+
+    ASSERT_FALSE(mLinker->linkAndValidate());
+}
+
+TEST_F(LinkerTest, ConvertRawStringToString) {
+    std::unique_ptr<Style> style = util::make_unique<Style>();
+    style->entries.push_back(Style::Entry{
+            ResourceNameRef{ u"android", ResourceType::kAttr, u"string" },
+            util::make_unique<RawString>(
+                    mTable->getValueStringPool().makeRef(u"  \"this  is  \\u00fa\"."))
+    });
+    const Style* result = style.get();
+    ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" },
+                std::move(style)));
+
+    ASSERT_TRUE(mLinker->linkAndValidate());
+    EXPECT_TRUE(mLinker->getUnresolvedReferences().empty());
+
+    const String* str = dynamic_cast<const String*>(result->entries.front().value.get());
+    ASSERT_NE(nullptr, str);
+    EXPECT_EQ(*str->value, u"this  is  \u00fa.");
+}
+
+TEST_F(LinkerTest, ConvertRawStringToFlags) {
+    std::unique_ptr<Style> style = util::make_unique<Style>();
+    style->entries.push_back(Style::Entry{
+            ResourceNameRef{ u"android", ResourceType::kAttr, u"flags" },
+            util::make_unique<RawString>(mTable->getValueStringPool().makeRef(u"banana | apple"))
+    });
+    const Style* result = style.get();
+    ASSERT_TRUE(addResource(ResourceName{ u"android", ResourceType::kStyle, u"foo" },
+                std::move(style)));
+
+    ASSERT_TRUE(mLinker->linkAndValidate());
+    EXPECT_TRUE(mLinker->getUnresolvedReferences().empty());
+
+    const BinaryPrimitive* bin = dynamic_cast<const BinaryPrimitive*>(
+            result->entries.front().value.get());
+    ASSERT_NE(nullptr, bin);
+    EXPECT_EQ(bin->value.data, 1u | 2u);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Locale.cpp b/tools/aapt2/Locale.cpp
new file mode 100644
index 0000000..eed0ea7
--- /dev/null
+++ b/tools/aapt2/Locale.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Locale.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <ctype.h>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+using android::ResTable_config;
+
+void LocaleValue::setLanguage(const char* languageChars) {
+     size_t i = 0;
+     while ((*languageChars) != '\0') {
+          language[i++] = ::tolower(*languageChars);
+          languageChars++;
+     }
+}
+
+void LocaleValue::setRegion(const char* regionChars) {
+    size_t i = 0;
+    while ((*regionChars) != '\0') {
+         region[i++] = ::toupper(*regionChars);
+         regionChars++;
+    }
+}
+
+void LocaleValue::setScript(const char* scriptChars) {
+    size_t i = 0;
+    while ((*scriptChars) != '\0') {
+         if (i == 0) {
+             script[i++] = ::toupper(*scriptChars);
+         } else {
+             script[i++] = ::tolower(*scriptChars);
+         }
+         scriptChars++;
+    }
+}
+
+void LocaleValue::setVariant(const char* variantChars) {
+     size_t i = 0;
+     while ((*variantChars) != '\0') {
+          variant[i++] = *variantChars;
+          variantChars++;
+     }
+}
+
+static inline bool isAlpha(const std::string& str) {
+    return std::all_of(std::begin(str), std::end(str), ::isalpha);
+}
+
+static inline bool isNumber(const std::string& str) {
+    return std::all_of(std::begin(str), std::end(str), ::isdigit);
+}
+
+bool LocaleValue::initFromFilterString(const std::string& str) {
+     // A locale (as specified in the filter) is an underscore separated name such
+     // as "en_US", "en_Latn_US", or "en_US_POSIX".
+     std::vector<std::string> parts = util::splitAndLowercase(str, '_');
+
+     const int numTags = parts.size();
+     bool valid = false;
+     if (numTags >= 1) {
+         const std::string& lang = parts[0];
+         if (isAlpha(lang) && (lang.length() == 2 || lang.length() == 3)) {
+             setLanguage(lang.c_str());
+             valid = true;
+         }
+     }
+
+     if (!valid || numTags == 1) {
+         return valid;
+     }
+
+     // At this point, valid == true && numTags > 1.
+     const std::string& part2 = parts[1];
+     if ((part2.length() == 2 && isAlpha(part2)) ||
+         (part2.length() == 3 && isNumber(part2))) {
+         setRegion(part2.c_str());
+     } else if (part2.length() == 4 && isAlpha(part2)) {
+         setScript(part2.c_str());
+     } else if (part2.length() >= 5 && part2.length() <= 8) {
+         setVariant(part2.c_str());
+     } else {
+         valid = false;
+     }
+
+     if (!valid || numTags == 2) {
+         return valid;
+     }
+
+     // At this point, valid == true && numTags > 1.
+     const std::string& part3 = parts[2];
+     if (((part3.length() == 2 && isAlpha(part3)) ||
+         (part3.length() == 3 && isNumber(part3))) && script[0]) {
+         setRegion(part3.c_str());
+     } else if (part3.length() >= 5 && part3.length() <= 8) {
+         setVariant(part3.c_str());
+     } else {
+         valid = false;
+     }
+
+     if (!valid || numTags == 3) {
+         return valid;
+     }
+
+     const std::string& part4 = parts[3];
+     if (part4.length() >= 5 && part4.length() <= 8) {
+         setVariant(part4.c_str());
+     } else {
+         valid = false;
+     }
+
+     if (!valid || numTags > 4) {
+         return false;
+     }
+
+     return true;
+}
+
+ssize_t LocaleValue::initFromParts(std::vector<std::string>::iterator iter,
+        std::vector<std::string>::iterator end) {
+    const std::vector<std::string>::iterator startIter = iter;
+
+    std::string& part = *iter;
+    if (part[0] == 'b' && part[1] == '+') {
+        // This is a "modified" BCP-47 language tag. Same semantics as BCP-47 tags,
+        // except that the separator is "+" and not "-".
+        std::vector<std::string> subtags = util::splitAndLowercase(part, '+');
+        subtags.erase(subtags.begin());
+        if (subtags.size() == 1) {
+            setLanguage(subtags[0].c_str());
+        } else if (subtags.size() == 2) {
+            setLanguage(subtags[0].c_str());
+
+            // The second tag can either be a region, a variant or a script.
+            switch (subtags[1].size()) {
+                case 2:
+                case 3:
+                    setRegion(subtags[1].c_str());
+                    break;
+                case 4:
+                    setScript(subtags[1].c_str());
+                    break;
+                case 5:
+                case 6:
+                case 7:
+                case 8:
+                    setVariant(subtags[1].c_str());
+                    break;
+                default:
+                    return -1;
+            }
+        } else if (subtags.size() == 3) {
+            // The language is always the first subtag.
+            setLanguage(subtags[0].c_str());
+
+            // The second subtag can either be a script or a region code.
+            // If its size is 4, it's a script code, else it's a region code.
+            if (subtags[1].size() == 4) {
+                setScript(subtags[1].c_str());
+            } else if (subtags[1].size() == 2 || subtags[1].size() == 3) {
+                setRegion(subtags[1].c_str());
+            } else {
+                return -1;
+            }
+
+            // The third tag can either be a region code (if the second tag was
+            // a script), else a variant code.
+            if (subtags[2].size() > 4) {
+                setVariant(subtags[2].c_str());
+            } else {
+                setRegion(subtags[2].c_str());
+            }
+        } else if (subtags.size() == 4) {
+            setLanguage(subtags[0].c_str());
+            setScript(subtags[1].c_str());
+            setRegion(subtags[2].c_str());
+            setVariant(subtags[3].c_str());
+        } else {
+            return -1;
+        }
+
+        ++iter;
+
+    } else {
+        if ((part.length() == 2 || part.length() == 3)
+                && isAlpha(part) && part != "car") {
+            setLanguage(part.c_str());
+            ++iter;
+
+            if (iter != end) {
+                const std::string& regionPart = *iter;
+                if (regionPart.c_str()[0] == 'r' && regionPart.length() == 3) {
+                    setRegion(regionPart.c_str() + 1);
+                    ++iter;
+                }
+            }
+        }
+    }
+
+    return static_cast<ssize_t>(iter - startIter);
+}
+
+
+std::string LocaleValue::toDirName() const {
+    std::string dirName;
+    if (language[0]) {
+        dirName += language;
+    } else {
+        return dirName;
+    }
+
+    if (script[0]) {
+        dirName += "-s";
+        dirName += script;
+    }
+
+    if (region[0]) {
+        dirName += "-r";
+        dirName += region;
+    }
+
+    if (variant[0]) {
+        dirName += "-v";
+        dirName += variant;
+    }
+
+    return dirName;
+}
+
+void LocaleValue::initFromResTable(const ResTable_config& config) {
+    config.unpackLanguage(language);
+    config.unpackRegion(region);
+    if (config.localeScript[0]) {
+        memcpy(script, config.localeScript, sizeof(config.localeScript));
+    }
+
+    if (config.localeVariant[0]) {
+        memcpy(variant, config.localeVariant, sizeof(config.localeVariant));
+    }
+}
+
+void LocaleValue::writeTo(ResTable_config* out) const {
+    out->packLanguage(language);
+    out->packRegion(region);
+
+    if (script[0]) {
+        memcpy(out->localeScript, script, sizeof(out->localeScript));
+    }
+
+    if (variant[0]) {
+        memcpy(out->localeVariant, variant, sizeof(out->localeVariant));
+    }
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Locale.h b/tools/aapt2/Locale.h
new file mode 100644
index 0000000..ceec764
--- /dev/null
+++ b/tools/aapt2/Locale.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_LOCALE_VALUE_H
+#define AAPT_LOCALE_VALUE_H
+
+#include <androidfw/ResourceTypes.h>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * A convenience class to build and parse locales.
+ */
+struct LocaleValue {
+    char language[4];
+    char region[4];
+    char script[4];
+    char variant[8];
+
+    inline LocaleValue();
+
+    /**
+     * Initialize this LocaleValue from a config string.
+     */
+    bool initFromFilterString(const std::string& config);
+
+    /**
+     * Initialize this LocaleValue from parts of a vector.
+     */
+    ssize_t initFromParts(std::vector<std::string>::iterator iter,
+            std::vector<std::string>::iterator end);
+
+    /**
+     * Initialize this LocaleValue from a ResTable_config.
+     */
+    void initFromResTable(const android::ResTable_config& config);
+
+    /**
+     * Set the locale in a ResTable_config from this LocaleValue.
+     */
+    void writeTo(android::ResTable_config* out) const;
+
+    std::string toDirName() const;
+
+    inline int compare(const LocaleValue& other) const;
+
+    inline bool operator<(const LocaleValue& o) const;
+    inline bool operator<=(const LocaleValue& o) const;
+    inline bool operator==(const LocaleValue& o) const;
+    inline bool operator!=(const LocaleValue& o) const;
+    inline bool operator>=(const LocaleValue& o) const;
+    inline bool operator>(const LocaleValue& o) const;
+
+private:
+     void setLanguage(const char* language);
+     void setRegion(const char* language);
+     void setScript(const char* script);
+     void setVariant(const char* variant);
+};
+
+//
+// Implementation
+//
+
+LocaleValue::LocaleValue() {
+    memset(this, 0, sizeof(LocaleValue));
+}
+
+int LocaleValue::compare(const LocaleValue& other) const {
+    return memcmp(this, &other, sizeof(LocaleValue));
+}
+
+bool LocaleValue::operator<(const LocaleValue& o) const {
+    return compare(o) < 0;
+}
+
+bool LocaleValue::operator<=(const LocaleValue& o) const {
+    return compare(o) <= 0;
+}
+
+bool LocaleValue::operator==(const LocaleValue& o) const {
+    return compare(o) == 0;
+}
+
+bool LocaleValue::operator!=(const LocaleValue& o) const {
+    return compare(o) != 0;
+}
+
+bool LocaleValue::operator>=(const LocaleValue& o) const {
+    return compare(o) >= 0;
+}
+
+bool LocaleValue::operator>(const LocaleValue& o) const {
+    return compare(o) > 0;
+}
+
+} // namespace aapt
+
+#endif // AAPT_LOCALE_VALUE_H
diff --git a/tools/aapt2/Locale_test.cpp b/tools/aapt2/Locale_test.cpp
new file mode 100644
index 0000000..4e154d6
--- /dev/null
+++ b/tools/aapt2/Locale_test.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Locale.h"
+#include "Util.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+namespace aapt {
+
+static ::testing::AssertionResult TestLanguage(const char* input, const char* lang) {
+    std::vector<std::string> parts = util::splitAndLowercase(std::string(input), '-');
+    LocaleValue lv;
+    ssize_t count = lv.initFromParts(std::begin(parts), std::end(parts));
+    if (count < 0) {
+        return ::testing::AssertionFailure() << " failed to parse '" << input << "'.";
+    }
+
+    if (count != 1) {
+        return ::testing::AssertionFailure() << count
+            << " parts were consumed parsing '" << input << "' but expected 1.";
+    }
+
+    if (memcmp(lv.language, lang, std::min(strlen(lang), sizeof(lv.language))) != 0) {
+        return ::testing::AssertionFailure() << "expected " << lang << " but got "
+            << std::string(lv.language, sizeof(lv.language)) << ".";
+    }
+
+    return ::testing::AssertionSuccess();
+}
+
+static ::testing::AssertionResult TestLanguageRegion(const char* input, const char* lang,
+                                                     const char* region) {
+    std::vector<std::string> parts = util::splitAndLowercase(std::string(input), '-');
+    LocaleValue lv;
+    ssize_t count = lv.initFromParts(std::begin(parts), std::end(parts));
+    if (count < 0) {
+        return ::testing::AssertionFailure() << " failed to parse '" << input << "'.";
+    }
+
+    if (count != 2) {
+        return ::testing::AssertionFailure() << count
+            << " parts were consumed parsing '" << input << "' but expected 2.";
+    }
+
+    if (memcmp(lv.language, lang, std::min(strlen(lang), sizeof(lv.language))) != 0) {
+        return ::testing::AssertionFailure() << "expected " << input << " but got "
+            << std::string(lv.language, sizeof(lv.language)) << ".";
+    }
+
+    if (memcmp(lv.region, region, std::min(strlen(region), sizeof(lv.region))) != 0) {
+        return ::testing::AssertionFailure() << "expected " << region << " but got "
+            << std::string(lv.region, sizeof(lv.region)) << ".";
+    }
+
+    return ::testing::AssertionSuccess();
+}
+
+TEST(ConfigDescriptionTest, ParseLanguage) {
+    EXPECT_TRUE(TestLanguage("en", "en"));
+    EXPECT_TRUE(TestLanguage("fr", "fr"));
+    EXPECT_FALSE(TestLanguage("land", ""));
+    EXPECT_TRUE(TestLanguage("fr-land", "fr"));
+
+    EXPECT_TRUE(TestLanguageRegion("fr-rCA", "fr", "CA"));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Logger.cpp b/tools/aapt2/Logger.cpp
new file mode 100644
index 0000000..3847185
--- /dev/null
+++ b/tools/aapt2/Logger.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Logger.h"
+#include "Source.h"
+
+#include <memory>
+#include <iostream>
+
+namespace aapt {
+
+Log::Log(std::ostream& _out, std::ostream& _err) : out(_out), err(_err) {
+}
+
+std::shared_ptr<Log> Logger::sLog(std::make_shared<Log>(std::cerr, std::cerr));
+
+void Logger::setLog(const std::shared_ptr<Log>& log) {
+    sLog = log;
+}
+
+std::ostream& Logger::error() {
+    return sLog->err << "error: ";
+}
+
+std::ostream& Logger::error(const Source& source) {
+    return sLog->err << source << ": error: ";
+}
+
+std::ostream& Logger::error(const SourceLine& source) {
+    return sLog->err << source << ": error: ";
+}
+
+std::ostream& Logger::warn() {
+    return sLog->err << "warning: ";
+}
+
+std::ostream& Logger::warn(const Source& source) {
+    return sLog->err << source << ": warning: ";
+}
+
+std::ostream& Logger::warn(const SourceLine& source) {
+    return sLog->err << source << ": warning: ";
+}
+
+std::ostream& Logger::note() {
+    return sLog->out << "note: ";
+}
+
+std::ostream& Logger::note(const Source& source) {
+    return sLog->err << source << ": note: ";
+}
+
+std::ostream& Logger::note(const SourceLine& source) {
+    return sLog->err << source << ": note: ";
+}
+
+SourceLogger::SourceLogger(const Source& source)
+: mSource(source) {
+}
+
+std::ostream& SourceLogger::error() {
+    return Logger::error(mSource);
+}
+
+std::ostream& SourceLogger::error(size_t line) {
+    return Logger::error(SourceLine{ mSource.path, line });
+}
+
+std::ostream& SourceLogger::warn() {
+    return Logger::warn(mSource);
+}
+
+std::ostream& SourceLogger::warn(size_t line) {
+    return Logger::warn(SourceLine{ mSource.path, line });
+}
+
+std::ostream& SourceLogger::note() {
+    return Logger::note(mSource);
+}
+
+std::ostream& SourceLogger::note(size_t line) {
+    return Logger::note(SourceLine{ mSource.path, line });
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Logger.h b/tools/aapt2/Logger.h
new file mode 100644
index 0000000..1d437eb
--- /dev/null
+++ b/tools/aapt2/Logger.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_LOGGER_H
+#define AAPT_LOGGER_H
+
+#include "Source.h"
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <utils/String8.h>
+
+namespace aapt {
+
+struct Log {
+    Log(std::ostream& out, std::ostream& err);
+    Log(const Log& rhs) = delete;
+
+    std::ostream& out;
+    std::ostream& err;
+};
+
+class Logger {
+public:
+    static void setLog(const std::shared_ptr<Log>& log);
+
+    static std::ostream& error();
+    static std::ostream& error(const Source& source);
+    static std::ostream& error(const SourceLine& sourceLine);
+
+    static std::ostream& warn();
+    static std::ostream& warn(const Source& source);
+    static std::ostream& warn(const SourceLine& sourceLine);
+
+    static std::ostream& note();
+    static std::ostream& note(const Source& source);
+    static std::ostream& note(const SourceLine& sourceLine);
+
+private:
+    static std::shared_ptr<Log> sLog;
+};
+
+class SourceLogger {
+public:
+    SourceLogger(const Source& source);
+
+    std::ostream& error();
+    std::ostream& error(size_t line);
+
+    std::ostream& warn();
+    std::ostream& warn(size_t line);
+
+    std::ostream& note();
+    std::ostream& note(size_t line);
+
+private:
+    Source mSource;
+};
+
+inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
+    android::String8 utf8(str.data(), str.size());
+    return out.write(utf8.string(), utf8.size());
+}
+
+} // namespace aapt
+
+#endif // AAPT_LOGGER_H
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
new file mode 100644
index 0000000..87127fd
--- /dev/null
+++ b/tools/aapt2/Main.cpp
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AppInfo.h"
+#include "BigBuffer.h"
+#include "BinaryResourceParser.h"
+#include "BindingXmlPullParser.h"
+#include "Files.h"
+#include "Flag.h"
+#include "JavaClassGenerator.h"
+#include "Linker.h"
+#include "ManifestParser.h"
+#include "ManifestValidator.h"
+#include "Png.h"
+#include "ResourceParser.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "SdkConstants.h"
+#include "SourceXmlPullParser.h"
+#include "StringPiece.h"
+#include "TableFlattener.h"
+#include "Util.h"
+#include "XmlFlattener.h"
+
+#include <algorithm>
+#include <androidfw/AssetManager.h>
+#include <cstdlib>
+#include <dirent.h>
+#include <errno.h>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <sys/stat.h>
+#include <utils/Errors.h>
+
+using namespace aapt;
+
+void printTable(const ResourceTable& table) {
+    std::cout << "ResourceTable package=" << table.getPackage();
+    if (table.getPackageId() != ResourceTable::kUnsetPackageId) {
+        std::cout << " id=" << std::hex << table.getPackageId() << std::dec;
+    }
+    std::cout << std::endl
+         << "---------------------------------------------------------" << std::endl;
+
+    for (const auto& type : table) {
+        std::cout << "Type " << type->type;
+        if (type->typeId != ResourceTableType::kUnsetTypeId) {
+            std::cout << " [" << type->typeId << "]";
+        }
+        std::cout << " (" << type->entries.size() << " entries)" << std::endl;
+        for (const auto& entry : type->entries) {
+            std::cout << "  " << entry->name;
+            if (entry->entryId != ResourceEntry::kUnsetEntryId) {
+                std::cout << " [" << entry->entryId << "]";
+            }
+            std::cout << " (" << entry->values.size() << " configurations)";
+            if (entry->publicStatus.isPublic) {
+                std::cout << " PUBLIC";
+            }
+            std::cout << std::endl;
+            for (const auto& value : entry->values) {
+                std::cout << "    " << value.config << " (" << value.source << ") : ";
+                value.value->print(std::cout);
+                std::cout << std::endl;
+            }
+        }
+    }
+}
+
+void printStringPool(const StringPool& pool) {
+    std::cout << "String pool of length " << pool.size() << std::endl
+         << "---------------------------------------------------------" << std::endl;
+
+    size_t i = 0;
+    for (const auto& entry : pool) {
+        std::cout << "[" << i << "]: "
+             << entry->value
+             << " (Priority " << entry->context.priority
+             << ", Config '" << entry->context.config << "')"
+             << std::endl;
+        i++;
+    }
+}
+
+std::unique_ptr<FileReference> makeFileReference(StringPool& pool, const StringPiece& filename,
+        ResourceType type, const ConfigDescription& config) {
+    std::stringstream path;
+    path << "res/" << type;
+    if (config != ConfigDescription{}) {
+        path << "-" << config;
+    }
+    path << "/" << filename;
+    return util::make_unique<FileReference>(pool.makeRef(util::utf8ToUtf16(path.str())));
+}
+
+/**
+ * Collect files from 'root', filtering out any files that do not
+ * match the FileFilter 'filter'.
+ */
+bool walkTree(const Source& root, const FileFilter& filter,
+              std::vector<Source>* outEntries) {
+    bool error = false;
+
+    for (const std::string& dirName : listFiles(root.path)) {
+        std::string dir = root.path;
+        appendPath(&dir, dirName);
+
+        FileType ft = getFileType(dir);
+        if (!filter(dirName, ft)) {
+            continue;
+        }
+
+        if (ft != FileType::kDirectory) {
+            continue;
+        }
+
+        for (const std::string& fileName : listFiles(dir)) {
+            std::string file(dir);
+            appendPath(&file, fileName);
+
+            FileType ft = getFileType(file);
+            if (!filter(fileName, ft)) {
+                continue;
+            }
+
+            if (ft != FileType::kRegular) {
+                Logger::error(Source{ file }) << "not a regular file." << std::endl;
+                error = true;
+                continue;
+            }
+            outEntries->push_back(Source{ file });
+        }
+    }
+    return !error;
+}
+
+bool loadBinaryResourceTable(std::shared_ptr<ResourceTable> table, const Source& source) {
+    std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
+    if (!ifs) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::streampos fsize = ifs.tellg();
+    ifs.seekg(0, std::ios::end);
+    fsize = ifs.tellg() - fsize;
+    ifs.seekg(0, std::ios::beg);
+
+    assert(fsize >= 0);
+    size_t dataSize = static_cast<size_t>(fsize);
+    char* buf = new char[dataSize];
+    ifs.read(buf, dataSize);
+
+    BinaryResourceParser parser(table, source, buf, dataSize);
+    bool result = parser.parse();
+
+    delete [] buf;
+    return result;
+}
+
+bool loadResTable(android::ResTable* table, const Source& source) {
+    std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
+    if (!ifs) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::streampos fsize = ifs.tellg();
+    ifs.seekg(0, std::ios::end);
+    fsize = ifs.tellg() - fsize;
+    ifs.seekg(0, std::ios::beg);
+
+    assert(fsize >= 0);
+    size_t dataSize = static_cast<size_t>(fsize);
+    char* buf = new char[dataSize];
+    ifs.read(buf, dataSize);
+
+    bool result = table->add(buf, dataSize, -1, true) == android::NO_ERROR;
+
+    delete [] buf;
+    return result;
+}
+
+void versionStylesForCompat(std::shared_ptr<ResourceTable> table) {
+    for (auto& type : *table) {
+        if (type->type != ResourceType::kStyle) {
+            continue;
+        }
+
+        for (auto& entry : type->entries) {
+            // Add the versioned styles we want to create
+            // here. They are added to the table after
+            // iterating over the original set of styles.
+            //
+            // A stack is used since auto-generated styles
+            // from later versions should override
+            // auto-generated styles from earlier versions.
+            // Iterating over the styles is done in order,
+            // so we will always visit sdkVersions from smallest
+            // to largest.
+            std::stack<ResourceConfigValue> addStack;
+
+            for (ResourceConfigValue& configValue : entry->values) {
+                visitFunc<Style>(*configValue.value, [&](Style& style) {
+                    // Collect which entries we've stripped and the smallest
+                    // SDK level which was stripped.
+                    size_t minSdkStripped = std::numeric_limits<size_t>::max();
+                    std::vector<Style::Entry> stripped;
+
+                    // Iterate over the style's entries and erase/record the
+                    // attributes whose SDK level exceeds the config's sdkVersion.
+                    auto iter = style.entries.begin();
+                    while (iter != style.entries.end()) {
+                        if (iter->key.name.package == u"android") {
+                            size_t sdkLevel = findAttributeSdkLevel(iter->key.name.entry);
+                            if (sdkLevel > 1 && sdkLevel > configValue.config.sdkVersion) {
+                                // Record that we are about to strip this.
+                                stripped.emplace_back(std::move(*iter));
+                                minSdkStripped = std::min(minSdkStripped, sdkLevel);
+
+                                // Erase this from this style.
+                                iter = style.entries.erase(iter);
+                                continue;
+                            }
+                        }
+                        ++iter;
+                    }
+
+                    if (!stripped.empty()) {
+                        // We have stripped attributes, so let's create a new style to hold them.
+                        ConfigDescription versionConfig(configValue.config);
+                        versionConfig.sdkVersion = minSdkStripped;
+
+                        ResourceConfigValue value = {
+                                versionConfig,
+                                configValue.source,
+                                {},
+
+                                // Create a copy of the original style.
+                                std::unique_ptr<Value>(configValue.value->clone())
+                        };
+
+                        Style& newStyle = static_cast<Style&>(*value.value);
+
+                        // Move the recorded stripped attributes into this new style.
+                        std::move(stripped.begin(), stripped.end(),
+                                  std::back_inserter(newStyle.entries));
+
+                        // We will add this style to the table later. If we do it now, we will
+                        // mess up iteration.
+                        addStack.push(std::move(value));
+                    }
+                });
+            }
+
+            auto comparator =
+                    [](const ResourceConfigValue& lhs, const ConfigDescription& rhs) -> bool {
+                        return lhs.config < rhs;
+                    };
+
+            while (!addStack.empty()) {
+                ResourceConfigValue& value = addStack.top();
+                auto iter = std::lower_bound(entry->values.begin(), entry->values.end(),
+                                             value.config, comparator);
+                if (iter == entry->values.end() || iter->config != value.config) {
+                    entry->values.insert(iter, std::move(value));
+                }
+                addStack.pop();
+            }
+        }
+    }
+}
+
+bool collectXml(std::shared_ptr<ResourceTable> table, const Source& source,
+                const ResourceName& name, const ConfigDescription& config) {
+    std::ifstream in(source.path, std::ifstream::binary);
+    if (!in) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::set<size_t> sdkLevels;
+
+    SourceXmlPullParser parser(in);
+    while (XmlPullParser::isGoodEvent(parser.next())) {
+        if (parser.getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        const auto endIter = parser.endAttributes();
+        for (auto iter = parser.beginAttributes(); iter != endIter; ++iter) {
+            if (iter->namespaceUri == u"http://schemas.android.com/apk/res/android") {
+                size_t sdkLevel = findAttributeSdkLevel(iter->name);
+                if (sdkLevel > 1) {
+                    sdkLevels.insert(sdkLevel);
+                }
+            }
+
+            ResourceNameRef refName;
+            bool create = false;
+            bool privateRef = false;
+            if (ResourceParser::tryParseReference(iter->value, &refName, &create, &privateRef) &&
+                    create) {
+                table->addResource(refName, {}, source.line(parser.getLineNumber()),
+                                   util::make_unique<Id>());
+            }
+        }
+    }
+
+    for (size_t level : sdkLevels) {
+        Logger::note(source)
+                << "creating v" << level << " versioned file."
+                << std::endl;
+        ConfigDescription newConfig = config;
+        newConfig.sdkVersion = level;
+
+        std::unique_ptr<FileReference> fileResource = makeFileReference(
+                table->getValueStringPool(),
+                util::utf16ToUtf8(name.entry) + ".xml",
+                name.type,
+                newConfig);
+        table->addResource(name, newConfig, source.line(0), std::move(fileResource));
+    }
+    return true;
+}
+
+struct CompileItem {
+    Source source;
+    ResourceName name;
+    ConfigDescription config;
+    std::string extension;
+};
+
+bool compileXml(std::shared_ptr<Resolver> resolver, const CompileItem& item,
+                const Source& outputSource, std::queue<CompileItem>* queue) {
+    std::ifstream in(item.source.path, std::ifstream::binary);
+    if (!in) {
+        Logger::error(item.source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::shared_ptr<BindingXmlPullParser> binding;
+    std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(in);
+    if (item.name.type == ResourceType::kLayout) {
+        binding = std::make_shared<BindingXmlPullParser>(xmlParser);
+        xmlParser = binding;
+    }
+
+    BigBuffer outBuffer(1024);
+    XmlFlattener flattener(resolver);
+
+    // We strip attributes that do not belong in this version of the resource.
+    // Non-version qualified resources have an implicit version 1 requirement.
+    XmlFlattener::Options options = { item.config.sdkVersion ? item.config.sdkVersion : 1 };
+    Maybe<size_t> minStrippedSdk = flattener.flatten(item.source, xmlParser, &outBuffer, options);
+    if (!minStrippedSdk) {
+        return false;
+    }
+
+    if (minStrippedSdk.value() > 0) {
+        // Something was stripped, so let's generate a new file
+        // with the version of the smallest SDK version stripped.
+        CompileItem newWork = item;
+        newWork.config.sdkVersion = minStrippedSdk.value();
+        queue->push(newWork);
+    }
+
+    std::ofstream out(outputSource.path, std::ofstream::binary);
+    if (!out) {
+        Logger::error(outputSource) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    if (!util::writeAll(out, outBuffer)) {
+        Logger::error(outputSource) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    if (binding) {
+        // We generated a binding xml file, write it out beside the output file.
+        Source bindingOutput = outputSource;
+        bindingOutput.path += ".bind.xml";
+        std::ofstream bout(bindingOutput.path);
+        if (!bout) {
+            Logger::error(bindingOutput) << strerror(errno) << std::endl;
+            return false;
+        }
+
+        if (!binding->writeToFile(bout)) {
+            Logger::error(bindingOutput) << strerror(errno) << std::endl;
+            return false;
+        }
+    }
+    return true;
+}
+
+bool compilePng(const Source& source, const Source& output) {
+    std::ifstream in(source.path, std::ifstream::binary);
+    if (!in) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::ofstream out(output.path, std::ofstream::binary);
+    if (!out) {
+        Logger::error(output) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::string err;
+    Png png;
+    if (!png.process(source, in, out, {}, &err)) {
+        Logger::error(source) << err << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool copyFile(const Source& source, const Source& output) {
+    std::ifstream in(source.path, std::ifstream::binary);
+    if (!in) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::ofstream out(output.path, std::ofstream::binary);
+    if (!out) {
+        Logger::error(output) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    if (out << in.rdbuf()) {
+        Logger::error(output) << strerror(errno) << std::endl;
+        return true;
+    }
+    return false;
+}
+
+struct AaptOptions {
+    enum class Phase {
+        Full,
+        Collect,
+        Link,
+        Compile,
+        Manifest
+    };
+
+    // The phase to process.
+    Phase phase;
+
+    // Details about the app.
+    AppInfo appInfo;
+
+    // The location of the manifest file.
+    Source manifest;
+
+    // The source directories to walk and find resource files.
+    std::vector<Source> sourceDirs;
+
+    // The resource files to process and collect.
+    std::vector<Source> collectFiles;
+
+    // The binary table files to link.
+    std::vector<Source> linkFiles;
+
+    // The resource files to compile.
+    std::vector<Source> compileFiles;
+
+    // The libraries these files may reference.
+    std::vector<Source> libraries;
+
+    // Output path. This can be a directory or file
+    // depending on the phase.
+    Source output;
+
+    // Directory to in which to generate R.java.
+    Maybe<Source> generateJavaClass;
+
+    // Whether to output verbose details about
+    // compilation.
+    bool verbose = false;
+};
+
+bool compileAndroidManifest(const std::shared_ptr<Resolver>& resolver,
+                            const AaptOptions& options) {
+    Source outSource = options.output;
+    appendPath(&outSource.path, "AndroidManifest.xml");
+
+    if (options.verbose) {
+        Logger::note(outSource) << "compiling AndroidManifest.xml." << std::endl;
+    }
+
+    std::ifstream in(options.manifest.path, std::ifstream::binary);
+    if (!in) {
+        Logger::error(options.manifest) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    BigBuffer outBuffer(1024);
+    std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(in);
+    XmlFlattener flattener(resolver);
+
+    Maybe<size_t> result = flattener.flatten(options.manifest, xmlParser, &outBuffer,
+                                             XmlFlattener::Options{});
+    if (!result) {
+        return false;
+    }
+
+    std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[outBuffer.size()]);
+    uint8_t* p = data.get();
+    for (const auto& b : outBuffer) {
+        memcpy(p, b.buffer.get(), b.size);
+        p += b.size;
+    }
+
+    android::ResXMLTree tree;
+    if (tree.setTo(data.get(), outBuffer.size()) != android::NO_ERROR) {
+        return false;
+    }
+
+    ManifestValidator validator(resolver->getResTable());
+    if (!validator.validate(options.manifest, &tree)) {
+        return false;
+    }
+
+    std::ofstream out(outSource.path, std::ofstream::binary);
+    if (!out) {
+        Logger::error(outSource) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    if (!util::writeAll(out, outBuffer)) {
+        Logger::error(outSource) << strerror(errno) << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool loadAppInfo(const Source& source, AppInfo* outInfo) {
+    std::ifstream ifs(source.path, std::ifstream::in | std::ifstream::binary);
+    if (!ifs) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    ManifestParser parser;
+    std::shared_ptr<XmlPullParser> pullParser = std::make_shared<SourceXmlPullParser>(ifs);
+    return parser.parse(source, pullParser, outInfo);
+}
+
+static AaptOptions prepareArgs(int argc, char** argv) {
+    if (argc < 2) {
+        std::cerr << "no command specified." << std::endl;
+        exit(1);
+    }
+
+    const StringPiece command(argv[1]);
+    argc -= 2;
+    argv += 2;
+
+    AaptOptions options;
+
+    StringPiece outputDescription = "place output in file";
+    if (command == "package") {
+        options.phase = AaptOptions::Phase::Full;
+        outputDescription = "place output in directory";
+    } else if (command == "collect") {
+        options.phase = AaptOptions::Phase::Collect;
+    } else if (command == "link") {
+        options.phase = AaptOptions::Phase::Link;
+    } else if (command == "compile") {
+        options.phase = AaptOptions::Phase::Compile;
+        outputDescription = "place output in directory";
+    } else if (command == "manifest") {
+        options.phase = AaptOptions::Phase::Manifest;
+        outputDescription = "place AndroidManifest.xml in directory";
+    } else {
+        std::cerr << "invalid command '" << command << "'." << std::endl;
+        exit(1);
+    }
+
+    if (options.phase == AaptOptions::Phase::Full) {
+        flag::requiredFlag("-S", "add a directory in which to find resources",
+                [&options](const StringPiece& arg) {
+                    options.sourceDirs.push_back(Source{ arg.toString() });
+                });
+
+        flag::requiredFlag("-M", "path to AndroidManifest.xml",
+                [&options](const StringPiece& arg) {
+                    options.manifest = Source{ arg.toString() };
+                });
+
+        flag::optionalFlag("-I", "add an Android APK to link against",
+                [&options](const StringPiece& arg) {
+                    options.libraries.push_back(Source{ arg.toString() });
+                });
+
+        flag::optionalFlag("--java", "directory in which to generate R.java",
+                [&options](const StringPiece& arg) {
+                    options.generateJavaClass = Source{ arg.toString() };
+                });
+
+    } else {
+        if (options.phase != AaptOptions::Phase::Manifest) {
+            flag::requiredFlag("--package", "Android package name",
+                    [&options](const StringPiece& arg) {
+                        options.appInfo.package = util::utf8ToUtf16(arg);
+                    });
+        }
+
+        if (options.phase != AaptOptions::Phase::Collect) {
+            flag::optionalFlag("-I", "add an Android APK to link against",
+                    [&options](const StringPiece& arg) {
+                        options.libraries.push_back(Source{ arg.toString() });
+                    });
+        }
+
+        if (options.phase == AaptOptions::Phase::Link) {
+            flag::optionalFlag("--java", "directory in which to generate R.java",
+                    [&options](const StringPiece& arg) {
+                        options.generateJavaClass = Source{ arg.toString() };
+                    });
+        }
+    }
+
+    // Common flags for all steps.
+    flag::requiredFlag("-o", outputDescription, [&options](const StringPiece& arg) {
+        options.output = Source{ arg.toString() };
+    });
+    flag::optionalSwitch("-v", "enables verbose logging", &options.verbose);
+
+    // Build the command string for output (eg. "aapt2 compile").
+    std::string fullCommand = "aapt2";
+    fullCommand += " ";
+    fullCommand += command.toString();
+
+    // Actually read the command line flags.
+    flag::parse(argc, argv, fullCommand);
+
+    // Copy all the remaining arguments.
+    if (options.phase == AaptOptions::Phase::Collect) {
+        for (const std::string& arg : flag::getArgs()) {
+            options.collectFiles.push_back(Source{ arg });
+        }
+    } else if (options.phase == AaptOptions::Phase::Compile) {
+        for (const std::string& arg : flag::getArgs()) {
+            options.compileFiles.push_back(Source{ arg });
+        }
+    } else if (options.phase == AaptOptions::Phase::Link) {
+        for (const std::string& arg : flag::getArgs()) {
+            options.linkFiles.push_back(Source{ arg });
+        }
+    } else if (options.phase == AaptOptions::Phase::Manifest) {
+        if (!flag::getArgs().empty()) {
+            options.manifest = Source{ flag::getArgs()[0] };
+        }
+    }
+    return options;
+}
+
+static bool collectValues(const std::shared_ptr<ResourceTable>& table, const Source& source,
+                          const ConfigDescription& config) {
+    std::ifstream in(source.path, std::ifstream::binary);
+    if (!in) {
+        Logger::error(source) << strerror(errno) << std::endl;
+        return false;
+    }
+
+    std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(in);
+    ResourceParser parser(table, source, config, xmlParser);
+    return parser.parse();
+}
+
+struct ResourcePathData {
+    std::u16string resourceDir;
+    std::u16string name;
+    std::string extension;
+    ConfigDescription config;
+};
+
+/**
+ * Resource file paths are expected to look like:
+ * [--/res/]type[-config]/name
+ */
+static Maybe<ResourcePathData> extractResourcePathData(const Source& source) {
+    std::vector<std::string> parts = util::splitAndLowercase(source.path, '/');
+    if (parts.size() < 2) {
+        Logger::error(source) << "bad resource path." << std::endl;
+        return {};
+    }
+
+    std::string& dir = parts[parts.size() - 2];
+    StringPiece dirStr = dir;
+
+    ConfigDescription config;
+    size_t dashPos = dir.find('-');
+    if (dashPos != std::string::npos) {
+        StringPiece configStr = dirStr.substr(dashPos + 1, dir.size() - (dashPos + 1));
+        if (!ConfigDescription::parse(configStr, &config)) {
+            Logger::error(source)
+                    << "invalid configuration '"
+                    << configStr
+                    << "'."
+                    << std::endl;
+            return {};
+        }
+        dirStr = dirStr.substr(0, dashPos);
+    }
+
+    std::string& filename = parts[parts.size() - 1];
+    StringPiece name = filename;
+    StringPiece extension;
+    size_t dotPos = filename.find('.');
+    if (dotPos != std::string::npos) {
+        extension = name.substr(dotPos + 1, filename.size() - (dotPos + 1));
+        name = name.substr(0, dotPos);
+    }
+
+    return ResourcePathData{
+            util::utf8ToUtf16(dirStr),
+            util::utf8ToUtf16(name),
+            extension.toString(),
+            config
+    };
+}
+
+bool doAll(AaptOptions* options, const std::shared_ptr<ResourceTable>& table,
+           const std::shared_ptr<Resolver>& resolver) {
+    const bool versionStyles = (options->phase == AaptOptions::Phase::Full ||
+            options->phase == AaptOptions::Phase::Link);
+    const bool verifyNoMissingSymbols = (options->phase == AaptOptions::Phase::Full ||
+            options->phase == AaptOptions::Phase::Link);
+    const bool compileFiles = (options->phase == AaptOptions::Phase::Full ||
+            options->phase == AaptOptions::Phase::Compile);
+    const bool flattenTable = (options->phase == AaptOptions::Phase::Full ||
+            options->phase == AaptOptions::Phase::Collect ||
+            options->phase == AaptOptions::Phase::Link);
+    const bool useExtendedChunks = options->phase == AaptOptions::Phase::Collect;
+
+    // Build the output table path.
+    Source outputTable = options->output;
+    if (options->phase == AaptOptions::Phase::Full) {
+        appendPath(&outputTable.path, "resources.arsc");
+    }
+
+    bool error = false;
+    std::queue<CompileItem> compileQueue;
+
+    // If source directories were specified, walk them looking for resource files.
+    if (!options->sourceDirs.empty()) {
+        const char* customIgnore = getenv("ANDROID_AAPT_IGNORE");
+        FileFilter fileFilter;
+        if (customIgnore && customIgnore[0]) {
+            fileFilter.setPattern(customIgnore);
+        } else {
+            fileFilter.setPattern(
+                    "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~");
+        }
+
+        for (const Source& source : options->sourceDirs) {
+            if (!walkTree(source, fileFilter, &options->collectFiles)) {
+                return false;
+            }
+        }
+    }
+
+    // Load all binary resource tables.
+    for (const Source& source : options->linkFiles) {
+        error |= !loadBinaryResourceTable(table, source);
+    }
+
+    if (error) {
+        return false;
+    }
+
+    // Collect all the resource files.
+    // Need to parse the resource type/config/filename.
+    for (const Source& source : options->collectFiles) {
+        Maybe<ResourcePathData> maybePathData = extractResourcePathData(source);
+        if (!maybePathData) {
+            return false;
+        }
+
+        const ResourcePathData& pathData = maybePathData.value();
+        if (pathData.resourceDir == u"values") {
+            if (options->verbose) {
+                Logger::note(source) << "collecting values..." << std::endl;
+            }
+
+            error |= !collectValues(table, source, pathData.config);
+            continue;
+        }
+
+        const ResourceType* type = parseResourceType(pathData.resourceDir);
+        if (!type) {
+            Logger::error(source) << "invalid resource type '" << pathData.resourceDir << "'."
+                                  << std::endl;
+            return false;
+        }
+
+        ResourceName resourceName = { table->getPackage(), *type, pathData.name };
+
+        // Add the file name to the resource table.
+        std::unique_ptr<FileReference> fileReference = makeFileReference(
+                table->getValueStringPool(),
+                util::utf16ToUtf8(pathData.name) + "." + pathData.extension,
+                *type, pathData.config);
+        error |= !table->addResource(resourceName, pathData.config, source.line(0),
+                                     std::move(fileReference));
+
+        if (pathData.extension == "xml") {
+            error |= !collectXml(table, source, resourceName, pathData.config);
+        }
+
+        compileQueue.push(
+                CompileItem{ source, resourceName, pathData.config, pathData.extension });
+    }
+
+    if (error) {
+        return false;
+    }
+
+    // Version all styles referencing attributes outside of their specified SDK version.
+    if (versionStyles) {
+        versionStylesForCompat(table);
+    }
+
+    // Verify that all references are valid.
+    Linker linker(table, resolver);
+    if (!linker.linkAndValidate()) {
+        return false;
+    }
+
+    // Verify that all symbols exist.
+    if (verifyNoMissingSymbols) {
+        const auto& unresolvedRefs = linker.getUnresolvedReferences();
+        if (!unresolvedRefs.empty()) {
+            for (const auto& entry : unresolvedRefs) {
+                for (const auto& source : entry.second) {
+                    Logger::error(source) << "unresolved symbol '" << entry.first << "'."
+                                          << std::endl;
+                }
+            }
+            return false;
+        }
+    }
+
+    // Compile files.
+    if (compileFiles) {
+        // First process any input compile files.
+        for (const Source& source : options->compileFiles) {
+            Maybe<ResourcePathData> maybePathData = extractResourcePathData(source);
+            if (!maybePathData) {
+                return false;
+            }
+
+            const ResourcePathData& pathData = maybePathData.value();
+            const ResourceType* type = parseResourceType(pathData.resourceDir);
+            if (!type) {
+                Logger::error(source) << "invalid resource type '" << pathData.resourceDir
+                                      << "'." << std::endl;
+                return false;
+            }
+
+            ResourceName resourceName = { table->getPackage(), *type, pathData.name };
+            compileQueue.push(
+                    CompileItem{ source, resourceName, pathData.config, pathData.extension });
+        }
+
+        // Now process the actual compile queue.
+        for (; !compileQueue.empty(); compileQueue.pop()) {
+            const CompileItem& item = compileQueue.front();
+
+            // Create the output directory path from the resource type and config.
+            std::stringstream outputPath;
+            outputPath << item.name.type;
+            if (item.config != ConfigDescription{}) {
+                outputPath << "-" << item.config.toString();
+            }
+
+            Source outSource = options->output;
+            appendPath(&outSource.path, "res");
+            appendPath(&outSource.path, outputPath.str());
+
+            // Make the directory.
+            if (!mkdirs(outSource.path)) {
+                Logger::error(outSource) << strerror(errno) << std::endl;
+                return false;
+            }
+
+            // Add the file name to the directory path.
+            appendPath(&outSource.path, util::utf16ToUtf8(item.name.entry) + "." + item.extension);
+
+            if (item.extension == "xml") {
+                if (options->verbose) {
+                    Logger::note(outSource) << "compiling XML file." << std::endl;
+                }
+
+                error |= !compileXml(resolver, item, outSource, &compileQueue);
+            } else if (item.extension == "png" || item.extension == "9.png") {
+                if (options->verbose) {
+                    Logger::note(outSource) << "compiling png file." << std::endl;
+                }
+
+                error |= !compilePng(item.source, outSource);
+            } else {
+                error |= !copyFile(item.source, outSource);
+            }
+        }
+
+        if (error) {
+            return false;
+        }
+    }
+
+    // Compile and validate the AndroidManifest.xml.
+    if (!options->manifest.path.empty()) {
+        if (!compileAndroidManifest(resolver, *options)) {
+            return false;
+        }
+    }
+
+    // Generate the Java class file.
+    if (options->generateJavaClass) {
+        Source outPath = options->generateJavaClass.value();
+        if (options->verbose) {
+            Logger::note() << "writing symbols to " << outPath << "." << std::endl;
+        }
+
+        // Build the output directory from the package name.
+        // Eg. com.android.app -> com/android/app
+        const std::string packageUtf8 = util::utf16ToUtf8(table->getPackage());
+        for (StringPiece part : util::tokenize<char>(packageUtf8, '.')) {
+            appendPath(&outPath.path, part);
+        }
+
+        if (!mkdirs(outPath.path)) {
+            Logger::error(outPath) << strerror(errno) << std::endl;
+            return false;
+        }
+
+        appendPath(&outPath.path, "R.java");
+
+        std::ofstream fout(outPath.path);
+        if (!fout) {
+            Logger::error(outPath) << strerror(errno) << std::endl;
+            return false;
+        }
+
+        JavaClassGenerator generator(table, {});
+        if (!generator.generate(fout)) {
+            Logger::error(outPath) << generator.getError() << "." << std::endl;
+            return false;
+        }
+    }
+
+    // Flatten the resource table.
+    if (flattenTable && table->begin() != table->end()) {
+        BigBuffer buffer(1024);
+        TableFlattener::Options tableOptions;
+        tableOptions.useExtendedChunks = useExtendedChunks;
+        TableFlattener flattener(tableOptions);
+        if (!flattener.flatten(&buffer, *table)) {
+            Logger::error() << "failed to flatten resource table." << std::endl;
+            return false;
+        }
+
+        if (options->verbose) {
+            Logger::note() << "Final resource table size=" << util::formatSize(buffer.size())
+                           << std::endl;
+        }
+
+        std::ofstream fout(outputTable.path, std::ofstream::binary);
+        if (!fout) {
+            Logger::error(outputTable) << strerror(errno) << "." << std::endl;
+            return false;
+        }
+
+        if (!util::writeAll(fout, buffer)) {
+            Logger::error(outputTable) << strerror(errno) << "." << std::endl;
+            return false;
+        }
+        fout.flush();
+    }
+    return true;
+}
+
+int main(int argc, char** argv) {
+    Logger::setLog(std::make_shared<Log>(std::cerr, std::cerr));
+    AaptOptions options = prepareArgs(argc, argv);
+
+    // If we specified a manifest, go ahead and load the package name from the manifest.
+    if (!options.manifest.path.empty()) {
+        if (!loadAppInfo(options.manifest, &options.appInfo)) {
+            return false;
+        }
+    }
+
+    // Verify we have some common options set.
+    if (options.appInfo.package.empty()) {
+        Logger::error() << "no package name specified." << std::endl;
+        return false;
+    }
+
+    // Every phase needs a resource table.
+    std::shared_ptr<ResourceTable> table = std::make_shared<ResourceTable>();
+    table->setPackage(options.appInfo.package);
+    if (options.appInfo.package == u"android") {
+        table->setPackageId(0x01);
+    } else {
+        table->setPackageId(0x7f);
+    }
+
+    // Load the included libraries.
+    std::shared_ptr<android::AssetManager> libraries = std::make_shared<android::AssetManager>();
+    for (const Source& source : options.libraries) {
+        if (util::stringEndsWith<char>(source.path, ".arsc")) {
+            // We'll process these last so as to avoid a cookie issue.
+            continue;
+        }
+
+        int32_t cookie;
+        if (!libraries->addAssetPath(android::String8(source.path.data()), &cookie)) {
+            Logger::error(source) << "failed to load library." << std::endl;
+            return false;
+        }
+    }
+
+    for (const Source& source : options.libraries) {
+        if (!util::stringEndsWith<char>(source.path, ".arsc")) {
+            // We've already processed this.
+            continue;
+        }
+
+        // Dirty hack but there is no other way to get a
+        // writeable ResTable.
+        if (!loadResTable(const_cast<android::ResTable*>(&libraries->getResources(false)),
+                          source)) {
+            return false;
+        }
+    }
+
+    // Make the resolver that will cache IDs for us.
+    std::shared_ptr<Resolver> resolver = std::make_shared<Resolver>(table, libraries);
+
+    // Do the work.
+    if (!doAll(&options, table, resolver)) {
+        Logger::error() << "aapt exiting with failures." << std::endl;
+        return 1;
+    }
+    return 0;
+}
diff --git a/tools/aapt2/ManifestParser.cpp b/tools/aapt2/ManifestParser.cpp
new file mode 100644
index 0000000..b8f0a43
--- /dev/null
+++ b/tools/aapt2/ManifestParser.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AppInfo.h"
+#include "Logger.h"
+#include "ManifestParser.h"
+#include "Source.h"
+#include "XmlPullParser.h"
+
+#include <string>
+
+namespace aapt {
+
+bool ManifestParser::parse(const Source& source, std::shared_ptr<XmlPullParser> parser,
+                           AppInfo* outInfo) {
+    SourceLogger logger = { source };
+
+    int depth = 0;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        XmlPullParser::Event event = parser->getEvent();
+        if (event == XmlPullParser::Event::kEndElement) {
+            depth--;
+            continue;
+        } else if (event != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        depth++;
+
+        const std::u16string& element = parser->getElementName();
+        if (depth == 1) {
+            if (element == u"manifest") {
+                if (!parseManifest(logger, parser, outInfo)) {
+                    return false;
+                }
+            } else {
+                logger.error()
+                        << "unexpected top-level element '"
+                        << element
+                        << "'."
+                        << std::endl;
+                return false;
+            }
+        } else {
+            XmlPullParser::skipCurrentElement(parser.get());
+        }
+    }
+
+    if (parser->getEvent() == XmlPullParser::Event::kBadDocument) {
+            logger.error(parser->getLineNumber())
+                << "failed to parse manifest: "
+                << parser->getLastError()
+                << "."
+                << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool ManifestParser::parseManifest(SourceLogger& logger, std::shared_ptr<XmlPullParser> parser,
+                                   AppInfo* outInfo) {
+    auto attrIter = parser->findAttribute(u"", u"package");
+    if (attrIter == parser->endAttributes() || attrIter->value.empty()) {
+        logger.error() << "no 'package' attribute found for element <manifest>." << std::endl;
+        return false;
+    }
+    outInfo->package = attrIter->value;
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ManifestParser.h b/tools/aapt2/ManifestParser.h
new file mode 100644
index 0000000..f2e43d4
--- /dev/null
+++ b/tools/aapt2/ManifestParser.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_MANIFEST_PARSER_H
+#define AAPT_MANIFEST_PARSER_H
+
+#include "AppInfo.h"
+#include "Logger.h"
+#include "Source.h"
+#include "XmlPullParser.h"
+
+namespace aapt {
+
+/*
+ * Parses an AndroidManifest.xml file and fills in an AppInfo structure with
+ * app data.
+ */
+class ManifestParser {
+public:
+    ManifestParser() = default;
+    ManifestParser(const ManifestParser&) = delete;
+
+    bool parse(const Source& source, std::shared_ptr<XmlPullParser> parser, AppInfo* outInfo);
+
+private:
+    bool parseManifest(SourceLogger& logger, std::shared_ptr<XmlPullParser> parser,
+                       AppInfo* outInfo);
+};
+
+} // namespace aapt
+
+#endif // AAPT_MANIFEST_PARSER_H
diff --git a/tools/aapt2/ManifestParser_test.cpp b/tools/aapt2/ManifestParser_test.cpp
new file mode 100644
index 0000000..be3a6fb
--- /dev/null
+++ b/tools/aapt2/ManifestParser_test.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AppInfo.h"
+#include "ManifestParser.h"
+#include "SourceXmlPullParser.h"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+TEST(ManifestParserTest, FindPackage) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+             "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+             "package=\"android\">\n"
+             "</manifest>\n";
+
+    ManifestParser parser;
+    AppInfo info;
+    std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(input);
+    ASSERT_TRUE(parser.parse(Source{ "AndroidManifest.xml" }, xmlParser, &info));
+
+    EXPECT_EQ(std::u16string(u"android"), info.package);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ManifestValidator.cpp b/tools/aapt2/ManifestValidator.cpp
new file mode 100644
index 0000000..7ec0bc7
--- /dev/null
+++ b/tools/aapt2/ManifestValidator.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Logger.h"
+#include "ManifestValidator.h"
+#include "Maybe.h"
+#include "Source.h"
+#include "Util.h"
+
+#include <androidfw/ResourceTypes.h>
+
+namespace aapt {
+
+ManifestValidator::ManifestValidator(const android::ResTable& table)
+: mTable(table) {
+}
+
+bool ManifestValidator::validate(const Source& source, android::ResXMLParser* parser) {
+    SourceLogger logger(source);
+
+    android::ResXMLParser::event_code_t code;
+    while ((code = parser->next()) != android::ResXMLParser::END_DOCUMENT &&
+            code != android::ResXMLParser::BAD_DOCUMENT) {
+        if (code != android::ResXMLParser::START_TAG) {
+            continue;
+        }
+
+        size_t len = 0;
+        const StringPiece16 namespaceUri(parser->getElementNamespace(&len), len);
+        if (!namespaceUri.empty()) {
+            continue;
+        }
+
+        const StringPiece16 name(parser->getElementName(&len), len);
+        if (name.empty()) {
+            logger.error(parser->getLineNumber())
+                    << "failed to get the element name."
+                    << std::endl;
+            return false;
+        }
+
+        if (name == u"manifest") {
+            if (!validateManifest(source, parser)) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+Maybe<StringPiece16> ManifestValidator::getAttributeValue(android::ResXMLParser* parser,
+                                                          size_t idx) {
+    android::Res_value value;
+    if (parser->getAttributeValue(idx, &value) < 0) {
+        return StringPiece16();
+    }
+
+    const android::ResStringPool* pool = &parser->getStrings();
+    if (value.dataType == android::Res_value::TYPE_REFERENCE) {
+        ssize_t strIdx = mTable.resolveReference(&value, 0x10000000u);
+        if (strIdx < 0) {
+            return {};
+        }
+        pool = mTable.getTableStringBlock(strIdx);
+    }
+
+    if (value.dataType != android::Res_value::TYPE_STRING || !pool) {
+        return {};
+    }
+    return util::getString(*pool, value.data);
+}
+
+Maybe<StringPiece16> ManifestValidator::getAttributeInlineValue(android::ResXMLParser* parser,
+                                                                size_t idx) {
+    android::Res_value value;
+    if (parser->getAttributeValue(idx, &value) < 0) {
+        return StringPiece16();
+    }
+
+    if (value.dataType != android::Res_value::TYPE_STRING) {
+        return {};
+    }
+    return util::getString(parser->getStrings(), value.data);
+}
+
+bool ManifestValidator::validateInlineAttribute(android::ResXMLParser* parser, size_t idx,
+                                                SourceLogger& logger,
+                                                const StringPiece16& charSet) {
+    size_t len = 0;
+    StringPiece16 element(parser->getElementName(&len), len);
+    StringPiece16 attributeName(parser->getAttributeName(idx, &len), len);
+    Maybe<StringPiece16> result = getAttributeInlineValue(parser, idx);
+    if (!result) {
+        logger.error(parser->getLineNumber())
+                << "<"
+                << element
+                << "> must have a '"
+                << attributeName
+                << "' attribute with a string literal value."
+                << std::endl;
+        return false;
+    }
+    return validateAttributeImpl(element, attributeName, result.value(), charSet,
+                                 parser->getLineNumber(), logger);
+}
+
+bool ManifestValidator::validateAttribute(android::ResXMLParser* parser, size_t idx,
+                                          SourceLogger& logger, const StringPiece16& charSet) {
+    size_t len = 0;
+    StringPiece16 element(parser->getElementName(&len), len);
+    StringPiece16 attributeName(parser->getAttributeName(idx, &len), len);
+    Maybe<StringPiece16> result = getAttributeValue(parser, idx);
+    if (!result) {
+        logger.error(parser->getLineNumber())
+                << "<"
+                << element
+                << "> must have a '"
+                << attributeName
+                << "' attribute that points to a string."
+                << std::endl;
+        return false;
+    }
+    return validateAttributeImpl(element, attributeName, result.value(), charSet,
+                                 parser->getLineNumber(), logger);
+}
+
+bool ManifestValidator::validateAttributeImpl(const StringPiece16& element,
+                                              const StringPiece16& attributeName,
+                                              const StringPiece16& attributeValue,
+                                              const StringPiece16& charSet, size_t lineNumber,
+                                              SourceLogger& logger) {
+    StringPiece16::const_iterator badIter =
+            util::findNonAlphaNumericAndNotInSet(attributeValue, charSet);
+    if (badIter != attributeValue.end()) {
+        logger.error(lineNumber)
+                << "tag <"
+                << element
+                << "> attribute '"
+                << attributeName
+                << "' has invalid character '"
+                << StringPiece16(badIter, 1)
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    if (!attributeValue.empty()) {
+        StringPiece16 trimmed = util::trimWhitespace(attributeValue);
+        if (attributeValue.begin() != trimmed.begin()) {
+            logger.error(lineNumber)
+                    << "tag <"
+                    << element
+                    << "> attribute '"
+                    << attributeName
+                    << "' can not start with whitespace."
+                    << std::endl;
+            return false;
+        }
+
+        if (attributeValue.end() != trimmed.end()) {
+            logger.error(lineNumber)
+                    << "tag <"
+                    << element
+                    << "> attribute '"
+                    << attributeName
+                    << "' can not end with whitespace."
+                    << std::endl;
+            return false;
+        }
+    }
+    return true;
+}
+
+constexpr const char16_t* kPackageIdentSet = u"._";
+
+bool ManifestValidator::validateManifest(const Source& source, android::ResXMLParser* parser) {
+    bool error = false;
+    SourceLogger logger(source);
+
+    const size_t attrCount = parser->getAttributeCount();
+    for (size_t i = 0; i < attrCount; i++) {
+        size_t len = 0;
+        StringPiece16 attrNamespace(parser->getAttributeNamespace(i, &len), len);
+        StringPiece16 attrName(parser->getAttributeName(i, &len), len);
+        if (attrNamespace.empty() && attrName == u"package") {
+            error |= !validateInlineAttribute(parser, i, logger, kPackageIdentSet);
+        } else if (attrNamespace == u"android") {
+            if (attrName == u"sharedUserId") {
+                error |= !validateInlineAttribute(parser, i, logger, kPackageIdentSet);
+            }
+        }
+    }
+    return !error;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ManifestValidator.h b/tools/aapt2/ManifestValidator.h
new file mode 100644
index 0000000..3188784
--- /dev/null
+++ b/tools/aapt2/ManifestValidator.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_MANIFEST_VALIDATOR_H
+#define AAPT_MANIFEST_VALIDATOR_H
+
+#include "Logger.h"
+#include "Maybe.h"
+#include "Source.h"
+#include "StringPiece.h"
+
+#include <androidfw/ResourceTypes.h>
+
+namespace aapt {
+
+class ManifestValidator {
+public:
+    ManifestValidator(const android::ResTable& table);
+    ManifestValidator(const ManifestValidator&) = delete;
+
+    bool validate(const Source& source, android::ResXMLParser* parser);
+
+private:
+    bool validateManifest(const Source& source, android::ResXMLParser* parser);
+
+    Maybe<StringPiece16> getAttributeInlineValue(android::ResXMLParser* parser, size_t idx);
+    Maybe<StringPiece16> getAttributeValue(android::ResXMLParser* parser, size_t idx);
+
+    bool validateInlineAttribute(android::ResXMLParser* parser, size_t idx,
+                                 SourceLogger& logger, const StringPiece16& charSet);
+    bool validateAttribute(android::ResXMLParser* parser, size_t idx, SourceLogger& logger,
+                           const StringPiece16& charSet);
+    bool validateAttributeImpl(const StringPiece16& element, const StringPiece16& attributeName,
+                               const StringPiece16& attributeValue, const StringPiece16& charSet,
+                               size_t lineNumber, SourceLogger& logger);
+
+    const android::ResTable& mTable;
+};
+
+} // namespace aapt
+
+#endif // AAPT_MANIFEST_VALIDATOR_H
diff --git a/tools/aapt2/Maybe.h b/tools/aapt2/Maybe.h
new file mode 100644
index 0000000..f6a396d
--- /dev/null
+++ b/tools/aapt2/Maybe.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_MAYBE_H
+#define AAPT_MAYBE_H
+
+#include <cassert>
+#include <type_traits>
+#include <utility>
+
+namespace aapt {
+
+/**
+ * Either holds a valid value of type T, or holds Nothing.
+ * The value is stored inline in this structure, so no
+ * heap memory is used when creating a Maybe<T> object.
+ */
+template <typename T>
+class Maybe {
+public:
+    /**
+     * Construct Nothing.
+     */
+    inline Maybe();
+
+    inline ~Maybe();
+
+    template <typename U>
+    inline Maybe(const Maybe<U>& rhs);
+
+    template <typename U>
+    inline Maybe(Maybe<U>&& rhs);
+
+    template <typename U>
+    inline Maybe& operator=(const Maybe<U>& rhs);
+
+    template <typename U>
+    inline Maybe& operator=(Maybe<U>&& rhs);
+
+    /**
+     * Construct a Maybe holding a value.
+     */
+    inline Maybe(const T& value);
+
+    /**
+     * Construct a Maybe holding a value.
+     */
+    inline Maybe(T&& value);
+
+    /**
+     * True if this holds a value, false if
+     * it holds Nothing.
+     */
+    inline operator bool() const;
+
+    /**
+     * Gets the value if one exists, or else
+     * panics.
+     */
+    inline T& value();
+
+    /**
+     * Gets the value if one exists, or else
+     * panics.
+     */
+    inline const T& value() const;
+
+private:
+    template <typename U>
+    friend class Maybe;
+
+    void destroy();
+
+    bool mNothing;
+
+    typename std::aligned_storage<sizeof(T), alignof(T)>::type mStorage;
+};
+
+template <typename T>
+Maybe<T>::Maybe()
+: mNothing(true) {
+}
+
+template <typename T>
+Maybe<T>::~Maybe() {
+    if (!mNothing) {
+        destroy();
+    }
+}
+
+template <typename T>
+template <typename U>
+Maybe<T>::Maybe(const Maybe<U>& rhs)
+: mNothing(rhs.mNothing) {
+    if (!rhs.mNothing) {
+        new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
+    }
+}
+
+template <typename T>
+template <typename U>
+Maybe<T>::Maybe(Maybe<U>&& rhs)
+: mNothing(rhs.mNothing) {
+    if (!rhs.mNothing) {
+        rhs.mNothing = true;
+
+        // Move the value from rhs.
+        new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
+
+        // Since the value in rhs is now Nothing,
+        // run the destructor for the value.
+        rhs.destroy();
+    }
+}
+
+template <typename T>
+template <typename U>
+Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) {
+    if (mNothing && rhs.mNothing) {
+        // Both are nothing, nothing to do.
+        return *this;
+    } else if  (!mNothing && !rhs.mNothing) {
+        // We both are something, so assign rhs to us.
+        reinterpret_cast<T&>(mStorage) = reinterpret_cast<const U&>(rhs.mStorage);
+    } else if (mNothing) {
+        // We are nothing but rhs is something.
+        mNothing = rhs.mNothing;
+
+        // Copy the value from rhs.
+        new (&mStorage) T(reinterpret_cast<const U&>(rhs.mStorage));
+    } else {
+        // We are something but rhs is nothing, so destroy our value.
+        mNothing = rhs.mNothing;
+        destroy();
+    }
+    return *this;
+}
+
+template <typename T>
+template <typename U>
+Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) {
+    if (mNothing && rhs.mNothing) {
+        // Both are nothing, nothing to do.
+        return *this;
+    } else if  (!mNothing && !rhs.mNothing) {
+        // We both are something, so move assign rhs to us.
+        rhs.mNothing = true;
+        reinterpret_cast<T&>(mStorage) = std::move(reinterpret_cast<U&>(rhs.mStorage));
+        rhs.destroy();
+    } else if (mNothing) {
+        // We are nothing but rhs is something.
+        mNothing = rhs.mNothing;
+
+        // Move the value from rhs.
+        new (&mStorage) T(std::move(reinterpret_cast<U&>(rhs.mStorage)));
+        rhs.destroy();
+    } else {
+        // We are something but rhs is nothing, so destroy our value.
+        mNothing = rhs.mNothing;
+        destroy();
+    }
+    return *this;
+}
+
+template <typename T>
+Maybe<T>::Maybe(const T& value)
+: mNothing(false) {
+    new (&mStorage) T(value);
+}
+
+template <typename T>
+Maybe<T>::Maybe(T&& value)
+: mNothing(false) {
+    new (&mStorage) T(std::forward<T>(value));
+}
+
+template <typename T>
+Maybe<T>::operator bool() const {
+    return !mNothing;
+}
+
+template <typename T>
+T& Maybe<T>::value() {
+    assert(!mNothing && "Maybe<T>::value() called on Nothing");
+    return reinterpret_cast<T&>(mStorage);
+}
+
+template <typename T>
+const T& Maybe<T>::value() const {
+    assert(!mNothing && "Maybe<T>::value() called on Nothing");
+    return reinterpret_cast<const T&>(mStorage);
+}
+
+template <typename T>
+void Maybe<T>::destroy() {
+    reinterpret_cast<T&>(mStorage).~T();
+}
+
+template <typename T>
+inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) {
+    return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value));
+}
+
+template <typename T>
+inline Maybe<T> make_nothing() {
+    return Maybe<T>();
+}
+
+} // namespace aapt
+
+#endif // AAPT_MAYBE_H
diff --git a/tools/aapt2/Maybe_test.cpp b/tools/aapt2/Maybe_test.cpp
new file mode 100644
index 0000000..348d7dd
--- /dev/null
+++ b/tools/aapt2/Maybe_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "Maybe.h"
+
+namespace aapt {
+
+struct Dummy {
+    Dummy() {
+        std::cerr << "Constructing Dummy " << (void *) this << std::endl;
+    }
+
+    Dummy(const Dummy& rhs) {
+        std::cerr << "Copying Dummy " << (void *) this << " from " << (const void*) &rhs << std::endl;
+    }
+
+    Dummy(Dummy&& rhs) {
+        std::cerr << "Moving Dummy " << (void *) this << " from " << (void*) &rhs << std::endl;
+    }
+
+    ~Dummy() {
+        std::cerr << "Destroying Dummy " << (void *) this << std::endl;
+    }
+};
+
+TEST(MaybeTest, MakeNothing) {
+    Maybe<int> val = make_nothing<int>();
+    EXPECT_FALSE(val);
+
+    Maybe<std::string> val2 = make_nothing<std::string>();
+    EXPECT_FALSE(val2);
+
+    val2 = make_nothing<std::string>();
+    EXPECT_FALSE(val2);
+}
+
+TEST(MaybeTest, MakeSomething) {
+    Maybe<int> val = make_value(23);
+    ASSERT_TRUE(val);
+    EXPECT_EQ(23, val.value());
+
+    Maybe<std::string> val2 = make_value(std::string("hey"));
+    ASSERT_TRUE(val2);
+    EXPECT_EQ(std::string("hey"), val2.value());
+}
+
+TEST(MaybeTest, Lifecycle) {
+    Maybe<Dummy> val = make_nothing<Dummy>();
+
+    Maybe<Dummy> val2 = make_value(Dummy());
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Png.cpp b/tools/aapt2/Png.cpp
new file mode 100644
index 0000000..76120ac
--- /dev/null
+++ b/tools/aapt2/Png.cpp
@@ -0,0 +1,1284 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Logger.h"
+#include "Png.h"
+#include "Source.h"
+#include "Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <iostream>
+#include <png.h>
+#include <sstream>
+#include <string>
+#include <vector>
+#include <zlib.h>
+
+namespace aapt {
+
+constexpr bool kDebug = false;
+constexpr size_t kPngSignatureSize = 8u;
+
+struct PngInfo {
+    ~PngInfo() {
+        for (png_bytep row : rows) {
+            if (row != nullptr) {
+                delete[] row;
+            }
+        }
+
+        delete[] xDivs;
+        delete[] yDivs;
+    }
+
+    void* serialize9Patch() {
+        void* serialized = android::Res_png_9patch::serialize(info9Patch, xDivs, yDivs,
+                                                              colors.data());
+        reinterpret_cast<android::Res_png_9patch*>(serialized)->deviceToFile();
+        return serialized;
+    }
+
+    uint32_t width = 0;
+    uint32_t height = 0;
+    std::vector<png_bytep> rows;
+
+    bool is9Patch = false;
+    android::Res_png_9patch info9Patch;
+    int32_t* xDivs = nullptr;
+    int32_t* yDivs = nullptr;
+    std::vector<uint32_t> colors;
+
+    // Layout padding.
+    bool haveLayoutBounds = false;
+    int32_t layoutBoundsLeft;
+    int32_t layoutBoundsTop;
+    int32_t layoutBoundsRight;
+    int32_t layoutBoundsBottom;
+
+    // Round rect outline description.
+    int32_t outlineInsetsLeft;
+    int32_t outlineInsetsTop;
+    int32_t outlineInsetsRight;
+    int32_t outlineInsetsBottom;
+    float outlineRadius;
+    uint8_t outlineAlpha;
+};
+
+static void readDataFromStream(png_structp readPtr, png_bytep data, png_size_t length) {
+    std::istream* input = reinterpret_cast<std::istream*>(png_get_io_ptr(readPtr));
+    if (!input->read(reinterpret_cast<char*>(data), length)) {
+        png_error(readPtr, strerror(errno));
+    }
+}
+
+static void writeDataToStream(png_structp writePtr, png_bytep data, png_size_t length) {
+    std::ostream* output = reinterpret_cast<std::ostream*>(png_get_io_ptr(writePtr));
+    if (!output->write(reinterpret_cast<const char*>(data), length)) {
+        png_error(writePtr, strerror(errno));
+    }
+}
+
+static void flushDataToStream(png_structp writePtr) {
+    std::ostream* output = reinterpret_cast<std::ostream*>(png_get_io_ptr(writePtr));
+    if (!output->flush()) {
+        png_error(writePtr, strerror(errno));
+    }
+}
+
+static void logWarning(png_structp readPtr, png_const_charp warningMessage) {
+    SourceLogger* logger = reinterpret_cast<SourceLogger*>(png_get_error_ptr(readPtr));
+    logger->warn() << warningMessage << "." << std::endl;
+}
+
+
+static bool readPng(png_structp readPtr, png_infop infoPtr, PngInfo* outInfo,
+                    std::string* outError) {
+    if (setjmp(png_jmpbuf(readPtr))) {
+        *outError = "failed reading png";
+        return false;
+    }
+
+    png_set_sig_bytes(readPtr, kPngSignatureSize);
+    png_read_info(readPtr, infoPtr);
+
+    int colorType, bitDepth, interlaceType, compressionType;
+    png_get_IHDR(readPtr, infoPtr, &outInfo->width, &outInfo->height, &bitDepth, &colorType,
+                 &interlaceType, &compressionType, nullptr);
+
+    if (colorType == PNG_COLOR_TYPE_PALETTE) {
+        png_set_palette_to_rgb(readPtr);
+    }
+
+    if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
+        png_set_expand_gray_1_2_4_to_8(readPtr);
+    }
+
+    if (png_get_valid(readPtr, infoPtr, PNG_INFO_tRNS)) {
+        png_set_tRNS_to_alpha(readPtr);
+    }
+
+    if (bitDepth == 16) {
+        png_set_strip_16(readPtr);
+    }
+
+    if (!(colorType & PNG_COLOR_MASK_ALPHA)) {
+        png_set_add_alpha(readPtr, 0xFF, PNG_FILLER_AFTER);
+    }
+
+    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        png_set_gray_to_rgb(readPtr);
+    }
+
+    png_set_interlace_handling(readPtr);
+    png_read_update_info(readPtr, infoPtr);
+
+    const uint32_t rowBytes = png_get_rowbytes(readPtr, infoPtr);
+    outInfo->rows.resize(outInfo->height);
+    for (size_t i = 0; i < outInfo->height; i++) {
+        outInfo->rows[i] = new png_byte[rowBytes];
+    }
+
+    png_read_image(readPtr, outInfo->rows.data());
+    png_read_end(readPtr, infoPtr);
+    return true;
+}
+
+static void checkNinePatchSerialization(android::Res_png_9patch* inPatch,  void* data) {
+    size_t patchSize = inPatch->serializedSize();
+    void* newData = malloc(patchSize);
+    memcpy(newData, data, patchSize);
+    android::Res_png_9patch* outPatch = inPatch->deserialize(newData);
+    outPatch->fileToDevice();
+    // deserialization is done in place, so outPatch == newData
+    assert(outPatch == newData);
+    assert(outPatch->numXDivs == inPatch->numXDivs);
+    assert(outPatch->numYDivs == inPatch->numYDivs);
+    assert(outPatch->paddingLeft == inPatch->paddingLeft);
+    assert(outPatch->paddingRight == inPatch->paddingRight);
+    assert(outPatch->paddingTop == inPatch->paddingTop);
+    assert(outPatch->paddingBottom == inPatch->paddingBottom);
+/*    for (int i = 0; i < outPatch->numXDivs; i++) {
+        assert(outPatch->getXDivs()[i] == inPatch->getXDivs()[i]);
+    }
+    for (int i = 0; i < outPatch->numYDivs; i++) {
+        assert(outPatch->getYDivs()[i] == inPatch->getYDivs()[i]);
+    }
+    for (int i = 0; i < outPatch->numColors; i++) {
+        assert(outPatch->getColors()[i] == inPatch->getColors()[i]);
+    }*/
+    free(newData);
+}
+
+/*static void dump_image(int w, int h, const png_byte* const* rows, int color_type) {
+    int i, j, rr, gg, bb, aa;
+
+    int bpp;
+    if (color_type == PNG_COLOR_TYPE_PALETTE || color_type == PNG_COLOR_TYPE_GRAY) {
+        bpp = 1;
+    } else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        bpp = 2;
+    } else if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
+        // We use a padding byte even when there is no alpha
+        bpp = 4;
+    } else {
+        printf("Unknown color type %d.\n", color_type);
+    }
+
+    for (j = 0; j < h; j++) {
+        const png_byte* row = rows[j];
+        for (i = 0; i < w; i++) {
+            rr = row[0];
+            gg = row[1];
+            bb = row[2];
+            aa = row[3];
+            row += bpp;
+
+            if (i == 0) {
+                printf("Row %d:", j);
+            }
+            switch (bpp) {
+            case 1:
+                printf(" (%d)", rr);
+                break;
+            case 2:
+                printf(" (%d %d", rr, gg);
+                break;
+            case 3:
+                printf(" (%d %d %d)", rr, gg, bb);
+                break;
+            case 4:
+                printf(" (%d %d %d %d)", rr, gg, bb, aa);
+                break;
+            }
+            if (i == (w - 1)) {
+                printf("\n");
+            }
+        }
+    }
+}*/
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define ABS(a)   ((a)<0?-(a):(a))
+
+static void analyze_image(SourceLogger* logger, const PngInfo& imageInfo, int grayscaleTolerance,
+                          png_colorp rgbPalette, png_bytep alphaPalette,
+                          int *paletteEntries, bool *hasTransparency, int *colorType,
+                          png_bytepp outRows) {
+    int w = imageInfo.width;
+    int h = imageInfo.height;
+    int i, j, rr, gg, bb, aa, idx;
+    uint32_t colors[256], col;
+    int num_colors = 0;
+    int maxGrayDeviation = 0;
+
+    bool isOpaque = true;
+    bool isPalette = true;
+    bool isGrayscale = true;
+
+    // Scan the entire image and determine if:
+    // 1. Every pixel has R == G == B (grayscale)
+    // 2. Every pixel has A == 255 (opaque)
+    // 3. There are no more than 256 distinct RGBA colors
+
+    if (kDebug) {
+        printf("Initial image data:\n");
+        //dump_image(w, h, imageInfo.rows.data(), PNG_COLOR_TYPE_RGB_ALPHA);
+    }
+
+    for (j = 0; j < h; j++) {
+        const png_byte* row = imageInfo.rows[j];
+        png_bytep out = outRows[j];
+        for (i = 0; i < w; i++) {
+            rr = *row++;
+            gg = *row++;
+            bb = *row++;
+            aa = *row++;
+
+            int odev = maxGrayDeviation;
+            maxGrayDeviation = MAX(ABS(rr - gg), maxGrayDeviation);
+            maxGrayDeviation = MAX(ABS(gg - bb), maxGrayDeviation);
+            maxGrayDeviation = MAX(ABS(bb - rr), maxGrayDeviation);
+            if (maxGrayDeviation > odev) {
+                if (kDebug) {
+                    printf("New max dev. = %d at pixel (%d, %d) = (%d %d %d %d)\n",
+                            maxGrayDeviation, i, j, rr, gg, bb, aa);
+                }
+            }
+
+            // Check if image is really grayscale
+            if (isGrayscale) {
+                if (rr != gg || rr != bb) {
+                    if (kDebug) {
+                        printf("Found a non-gray pixel at %d, %d = (%d %d %d %d)\n",
+                                i, j, rr, gg, bb, aa);
+                    }
+                    isGrayscale = false;
+                }
+            }
+
+            // Check if image is really opaque
+            if (isOpaque) {
+                if (aa != 0xff) {
+                    if (kDebug) {
+                        printf("Found a non-opaque pixel at %d, %d = (%d %d %d %d)\n",
+                                i, j, rr, gg, bb, aa);
+                    }
+                    isOpaque = false;
+                }
+            }
+
+            // Check if image is really <= 256 colors
+            if (isPalette) {
+                col = (uint32_t) ((rr << 24) | (gg << 16) | (bb << 8) | aa);
+                bool match = false;
+                for (idx = 0; idx < num_colors; idx++) {
+                    if (colors[idx] == col) {
+                        match = true;
+                        break;
+                    }
+                }
+
+                // Write the palette index for the pixel to outRows optimistically
+                // We might overwrite it later if we decide to encode as gray or
+                // gray + alpha
+                *out++ = idx;
+                if (!match) {
+                    if (num_colors == 256) {
+                        if (kDebug) {
+                            printf("Found 257th color at %d, %d\n", i, j);
+                        }
+                        isPalette = false;
+                    } else {
+                        colors[num_colors++] = col;
+                    }
+                }
+            }
+        }
+    }
+
+    *paletteEntries = 0;
+    *hasTransparency = !isOpaque;
+    int bpp = isOpaque ? 3 : 4;
+    int paletteSize = w * h + bpp * num_colors;
+
+    if (kDebug) {
+        printf("isGrayscale = %s\n", isGrayscale ? "true" : "false");
+        printf("isOpaque = %s\n", isOpaque ? "true" : "false");
+        printf("isPalette = %s\n", isPalette ? "true" : "false");
+        printf("Size w/ palette = %d, gray+alpha = %d, rgb(a) = %d\n",
+                paletteSize, 2 * w * h, bpp * w * h);
+        printf("Max gray deviation = %d, tolerance = %d\n", maxGrayDeviation, grayscaleTolerance);
+    }
+
+    // Choose the best color type for the image.
+    // 1. Opaque gray - use COLOR_TYPE_GRAY at 1 byte/pixel
+    // 2. Gray + alpha - use COLOR_TYPE_PALETTE if the number of distinct combinations
+    //     is sufficiently small, otherwise use COLOR_TYPE_GRAY_ALPHA
+    // 3. RGB(A) - use COLOR_TYPE_PALETTE if the number of distinct colors is sufficiently
+    //     small, otherwise use COLOR_TYPE_RGB{_ALPHA}
+    if (isGrayscale) {
+        if (isOpaque) {
+            *colorType = PNG_COLOR_TYPE_GRAY; // 1 byte/pixel
+        } else {
+            // Use a simple heuristic to determine whether using a palette will
+            // save space versus using gray + alpha for each pixel.
+            // This doesn't take into account chunk overhead, filtering, LZ
+            // compression, etc.
+            if (isPalette && (paletteSize < 2 * w * h)) {
+                *colorType = PNG_COLOR_TYPE_PALETTE; // 1 byte/pixel + 4 bytes/color
+            } else {
+                *colorType = PNG_COLOR_TYPE_GRAY_ALPHA; // 2 bytes per pixel
+            }
+        }
+    } else if (isPalette && (paletteSize < bpp * w * h)) {
+        *colorType = PNG_COLOR_TYPE_PALETTE;
+    } else {
+        if (maxGrayDeviation <= grayscaleTolerance) {
+            logger->note() << "forcing image to gray (max deviation = " << maxGrayDeviation
+                           << ")."
+                           << std::endl;
+            *colorType = isOpaque ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_GRAY_ALPHA;
+        } else {
+            *colorType = isOpaque ? PNG_COLOR_TYPE_RGB : PNG_COLOR_TYPE_RGB_ALPHA;
+        }
+    }
+
+    // Perform postprocessing of the image or palette data based on the final
+    // color type chosen
+
+    if (*colorType == PNG_COLOR_TYPE_PALETTE) {
+        // Create separate RGB and Alpha palettes and set the number of colors
+        *paletteEntries = num_colors;
+
+        // Create the RGB and alpha palettes
+        for (int idx = 0; idx < num_colors; idx++) {
+            col = colors[idx];
+            rgbPalette[idx].red   = (png_byte) ((col >> 24) & 0xff);
+            rgbPalette[idx].green = (png_byte) ((col >> 16) & 0xff);
+            rgbPalette[idx].blue  = (png_byte) ((col >>  8) & 0xff);
+            alphaPalette[idx]     = (png_byte)  (col        & 0xff);
+        }
+    } else if (*colorType == PNG_COLOR_TYPE_GRAY || *colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+        // If the image is gray or gray + alpha, compact the pixels into outRows
+        for (j = 0; j < h; j++) {
+            const png_byte* row = imageInfo.rows[j];
+            png_bytep out = outRows[j];
+            for (i = 0; i < w; i++) {
+                rr = *row++;
+                gg = *row++;
+                bb = *row++;
+                aa = *row++;
+
+                if (isGrayscale) {
+                    *out++ = rr;
+                } else {
+                    *out++ = (png_byte) (rr * 0.2126f + gg * 0.7152f + bb * 0.0722f);
+                }
+                if (!isOpaque) {
+                    *out++ = aa;
+                }
+           }
+        }
+    }
+}
+
+static bool writePng(png_structp writePtr, png_infop infoPtr, PngInfo* info,
+                     int grayScaleTolerance, SourceLogger* logger, std::string* outError) {
+    if (setjmp(png_jmpbuf(writePtr))) {
+        *outError = "failed to write png";
+        return false;
+    }
+
+    uint32_t width, height;
+    int colorType, bitDepth, interlaceType, compressionType;
+
+    png_unknown_chunk unknowns[3];
+    unknowns[0].data = nullptr;
+    unknowns[1].data = nullptr;
+    unknowns[2].data = nullptr;
+
+    png_bytepp outRows = (png_bytepp) malloc((int) info->height * sizeof(png_bytep));
+    if (outRows == (png_bytepp) 0) {
+        printf("Can't allocate output buffer!\n");
+        exit(1);
+    }
+    for (uint32_t i = 0; i < info->height; i++) {
+        outRows[i] = (png_bytep) malloc(2 * (int) info->width);
+        if (outRows[i] == (png_bytep) 0) {
+            printf("Can't allocate output buffer!\n");
+            exit(1);
+        }
+    }
+
+    png_set_compression_level(writePtr, Z_BEST_COMPRESSION);
+
+    if (kDebug) {
+        logger->note() << "writing image: w = " << info->width
+                       << ", h = " << info->height
+                       << std::endl;
+    }
+
+    png_color rgbPalette[256];
+    png_byte alphaPalette[256];
+    bool hasTransparency;
+    int paletteEntries;
+
+    analyze_image(logger, *info, grayScaleTolerance, rgbPalette, alphaPalette,
+                  &paletteEntries, &hasTransparency, &colorType, outRows);
+
+    // If the image is a 9-patch, we need to preserve it as a ARGB file to make
+    // sure the pixels will not be pre-dithered/clamped until we decide they are
+    if (info->is9Patch && (colorType == PNG_COLOR_TYPE_RGB ||
+            colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_PALETTE)) {
+        colorType = PNG_COLOR_TYPE_RGB_ALPHA;
+    }
+
+    if (kDebug) {
+        switch (colorType) {
+        case PNG_COLOR_TYPE_PALETTE:
+            logger->note() << "has " << paletteEntries
+                           << " colors" << (hasTransparency ? " (with alpha)" : "")
+                           << ", using PNG_COLOR_TYPE_PALLETTE."
+                           << std::endl;
+            break;
+        case PNG_COLOR_TYPE_GRAY:
+            logger->note() << "is opaque gray, using PNG_COLOR_TYPE_GRAY." << std::endl;
+            break;
+        case PNG_COLOR_TYPE_GRAY_ALPHA:
+            logger->note() << "is gray + alpha, using PNG_COLOR_TYPE_GRAY_ALPHA." << std::endl;
+            break;
+        case PNG_COLOR_TYPE_RGB:
+            logger->note() << "is opaque RGB, using PNG_COLOR_TYPE_RGB." << std::endl;
+            break;
+        case PNG_COLOR_TYPE_RGB_ALPHA:
+            logger->note() << "is RGB + alpha, using PNG_COLOR_TYPE_RGB_ALPHA." << std::endl;
+            break;
+        }
+    }
+
+    png_set_IHDR(writePtr, infoPtr, info->width, info->height, 8, colorType,
+                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    if (colorType == PNG_COLOR_TYPE_PALETTE) {
+        png_set_PLTE(writePtr, infoPtr, rgbPalette, paletteEntries);
+        if (hasTransparency) {
+            png_set_tRNS(writePtr, infoPtr, alphaPalette, paletteEntries, (png_color_16p) 0);
+        }
+        png_set_filter(writePtr, 0, PNG_NO_FILTERS);
+    } else {
+        png_set_filter(writePtr, 0, PNG_ALL_FILTERS);
+    }
+
+    if (info->is9Patch) {
+        int chunkCount = 2 + (info->haveLayoutBounds ? 1 : 0);
+        int pIndex = info->haveLayoutBounds ? 2 : 1;
+        int bIndex = 1;
+        int oIndex = 0;
+
+        // Chunks ordered thusly because older platforms depend on the base 9 patch data being last
+        png_bytep chunkNames = info->haveLayoutBounds
+                ? (png_bytep)"npOl\0npLb\0npTc\0"
+                : (png_bytep)"npOl\0npTc";
+
+        // base 9 patch data
+        if (kDebug) {
+            logger->note() << "adding 9-patch info..." << std::endl;
+        }
+        strcpy((char*)unknowns[pIndex].name, "npTc");
+        unknowns[pIndex].data = (png_byte*) info->serialize9Patch();
+        unknowns[pIndex].size = info->info9Patch.serializedSize();
+        // TODO: remove the check below when everything works
+        checkNinePatchSerialization(&info->info9Patch, unknowns[pIndex].data);
+
+        // automatically generated 9 patch outline data
+        int chunkSize = sizeof(png_uint_32) * 6;
+        strcpy((char*)unknowns[oIndex].name, "npOl");
+        unknowns[oIndex].data = (png_byte*) calloc(chunkSize, 1);
+        png_byte outputData[chunkSize];
+        memcpy(&outputData, &info->outlineInsetsLeft, 4 * sizeof(png_uint_32));
+        ((float*) outputData)[4] = info->outlineRadius;
+        ((png_uint_32*) outputData)[5] = info->outlineAlpha;
+        memcpy(unknowns[oIndex].data, &outputData, chunkSize);
+        unknowns[oIndex].size = chunkSize;
+
+        // optional optical inset / layout bounds data
+        if (info->haveLayoutBounds) {
+            int chunkSize = sizeof(png_uint_32) * 4;
+            strcpy((char*)unknowns[bIndex].name, "npLb");
+            unknowns[bIndex].data = (png_byte*) calloc(chunkSize, 1);
+            memcpy(unknowns[bIndex].data, &info->layoutBoundsLeft, chunkSize);
+            unknowns[bIndex].size = chunkSize;
+        }
+
+        for (int i = 0; i < chunkCount; i++) {
+            unknowns[i].location = PNG_HAVE_PLTE;
+        }
+        png_set_keep_unknown_chunks(writePtr, PNG_HANDLE_CHUNK_ALWAYS,
+                                    chunkNames, chunkCount);
+        png_set_unknown_chunks(writePtr, infoPtr, unknowns, chunkCount);
+
+#if PNG_LIBPNG_VER < 10600
+        // Deal with unknown chunk location bug in 1.5.x and earlier.
+        png_set_unknown_chunk_location(writePtr, infoPtr, 0, PNG_HAVE_PLTE);
+        if (info->haveLayoutBounds) {
+            png_set_unknown_chunk_location(writePtr, infoPtr, 1, PNG_HAVE_PLTE);
+        }
+#endif
+    }
+
+    png_write_info(writePtr, infoPtr);
+
+    png_bytepp rows;
+    if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) {
+        if (colorType == PNG_COLOR_TYPE_RGB) {
+            png_set_filler(writePtr, 0, PNG_FILLER_AFTER);
+        }
+        rows = info->rows.data();
+    } else {
+        rows = outRows;
+    }
+    png_write_image(writePtr, rows);
+
+    if (kDebug) {
+        printf("Final image data:\n");
+        //dump_image(info->width, info->height, rows, colorType);
+    }
+
+    png_write_end(writePtr, infoPtr);
+
+    for (uint32_t i = 0; i < info->height; i++) {
+        free(outRows[i]);
+    }
+    free(outRows);
+    free(unknowns[0].data);
+    free(unknowns[1].data);
+    free(unknowns[2].data);
+
+    png_get_IHDR(writePtr, infoPtr, &width, &height, &bitDepth, &colorType, &interlaceType,
+                 &compressionType, nullptr);
+
+    if (kDebug) {
+        logger->note() << "image written: w = " << width << ", h = " << height
+                       << ", d = " << bitDepth << ", colors = " << colorType
+                       << ", inter = " << interlaceType << ", comp = " << compressionType
+                       << std::endl;
+    }
+    return true;
+}
+
+constexpr uint32_t kColorWhite = 0xffffffffu;
+constexpr uint32_t kColorTick = 0xff000000u;
+constexpr uint32_t kColorLayoutBoundsTick = 0xff0000ffu;
+
+enum class TickType {
+    kNone,
+    kTick,
+    kLayoutBounds,
+    kBoth
+};
+
+static TickType tickType(png_bytep p, bool transparent, const char** outError) {
+    png_uint_32 color = p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
+
+    if (transparent) {
+        if (p[3] == 0) {
+            return TickType::kNone;
+        }
+        if (color == kColorLayoutBoundsTick) {
+            return TickType::kLayoutBounds;
+        }
+        if (color == kColorTick) {
+            return TickType::kTick;
+        }
+
+        // Error cases
+        if (p[3] != 0xff) {
+            *outError = "Frame pixels must be either solid or transparent "
+                        "(not intermediate alphas)";
+            return TickType::kNone;
+        }
+
+        if (p[0] != 0 || p[1] != 0 || p[2] != 0) {
+            *outError = "Ticks in transparent frame must be black or red";
+        }
+        return TickType::kTick;
+    }
+
+    if (p[3] != 0xFF) {
+        *outError = "White frame must be a solid color (no alpha)";
+    }
+    if (color == kColorWhite) {
+        return TickType::kNone;
+    }
+    if (color == kColorTick) {
+        return TickType::kTick;
+    }
+    if (color == kColorLayoutBoundsTick) {
+        return TickType::kLayoutBounds;
+    }
+
+    if (p[0] != 0 || p[1] != 0 || p[2] != 0) {
+        *outError = "Ticks in white frame must be black or red";
+        return TickType::kNone;
+    }
+    return TickType::kTick;
+}
+
+enum class TickState {
+    kStart,
+    kInside1,
+    kOutside1
+};
+
+static bool getHorizontalTicks(png_bytep row, int width, bool transparent, bool required,
+                               int32_t* outLeft, int32_t* outRight, const char** outError,
+                               uint8_t* outDivs, bool multipleAllowed) {
+    *outLeft = *outRight = -1;
+    TickState state = TickState::kStart;
+    bool found = false;
+
+    for (int i = 1; i < width - 1; i++) {
+        if (tickType(row+i*4, transparent, outError) == TickType::kTick) {
+            if (state == TickState::kStart ||
+                (state == TickState::kOutside1 && multipleAllowed)) {
+                *outLeft = i-1;
+                *outRight = width-2;
+                found = true;
+                if (outDivs != NULL) {
+                    *outDivs += 2;
+                }
+                state = TickState::kInside1;
+            } else if (state == TickState::kOutside1) {
+                *outError = "Can't have more than one marked region along edge";
+                *outLeft = i;
+                return false;
+            }
+        } else if (!*outError) {
+            if (state == TickState::kInside1) {
+                // We're done with this div.  Move on to the next.
+                *outRight = i-1;
+                outRight += 2;
+                outLeft += 2;
+                state = TickState::kOutside1;
+            }
+        } else {
+            *outLeft = i;
+            return false;
+        }
+    }
+
+    if (required && !found) {
+        *outError = "No marked region found along edge";
+        *outLeft = -1;
+        return false;
+    }
+    return true;
+}
+
+static bool getVerticalTicks(png_bytepp rows, int offset, int height, bool transparent,
+                             bool required, int32_t* outTop, int32_t* outBottom,
+                             const char** outError, uint8_t* outDivs, bool multipleAllowed) {
+    *outTop = *outBottom = -1;
+    TickState state = TickState::kStart;
+    bool found = false;
+
+    for (int i = 1; i < height - 1; i++) {
+        if (tickType(rows[i]+offset, transparent, outError) == TickType::kTick) {
+            if (state == TickState::kStart ||
+                (state == TickState::kOutside1 && multipleAllowed)) {
+                *outTop = i-1;
+                *outBottom = height-2;
+                found = true;
+                if (outDivs != NULL) {
+                    *outDivs += 2;
+                }
+                state = TickState::kInside1;
+            } else if (state == TickState::kOutside1) {
+                *outError = "Can't have more than one marked region along edge";
+                *outTop = i;
+                return false;
+            }
+        } else if (!*outError) {
+            if (state == TickState::kInside1) {
+                // We're done with this div.  Move on to the next.
+                *outBottom = i-1;
+                outTop += 2;
+                outBottom += 2;
+                state = TickState::kOutside1;
+            }
+        } else {
+            *outTop = i;
+            return false;
+        }
+    }
+
+    if (required && !found) {
+        *outError = "No marked region found along edge";
+        *outTop = -1;
+        return false;
+    }
+    return true;
+}
+
+static bool getHorizontalLayoutBoundsTicks(png_bytep row, int width, bool transparent,
+                                           bool /* required */, int32_t* outLeft,
+                                           int32_t* outRight, const char** outError) {
+    *outLeft = *outRight = 0;
+
+    // Look for left tick
+    if (tickType(row + 4, transparent, outError) == TickType::kLayoutBounds) {
+        // Starting with a layout padding tick
+        int i = 1;
+        while (i < width - 1) {
+            (*outLeft)++;
+            i++;
+            if (tickType(row + i * 4, transparent, outError) != TickType::kLayoutBounds) {
+                break;
+            }
+        }
+    }
+
+    // Look for right tick
+    if (tickType(row + (width - 2) * 4, transparent, outError) == TickType::kLayoutBounds) {
+        // Ending with a layout padding tick
+        int i = width - 2;
+        while (i > 1) {
+            (*outRight)++;
+            i--;
+            if (tickType(row+i*4, transparent, outError) != TickType::kLayoutBounds) {
+                break;
+            }
+        }
+    }
+    return true;
+}
+
+static bool getVerticalLayoutBoundsTicks(png_bytepp rows, int offset, int height, bool transparent,
+                                         bool /* required */, int32_t* outTop, int32_t* outBottom,
+                                         const char** outError) {
+    *outTop = *outBottom = 0;
+
+    // Look for top tick
+    if (tickType(rows[1] + offset, transparent, outError) == TickType::kLayoutBounds) {
+        // Starting with a layout padding tick
+        int i = 1;
+        while (i < height - 1) {
+            (*outTop)++;
+            i++;
+            if (tickType(rows[i] + offset, transparent, outError) != TickType::kLayoutBounds) {
+                break;
+            }
+        }
+    }
+
+    // Look for bottom tick
+    if (tickType(rows[height - 2] + offset, transparent, outError) == TickType::kLayoutBounds) {
+        // Ending with a layout padding tick
+        int i = height - 2;
+        while (i > 1) {
+            (*outBottom)++;
+            i--;
+            if (tickType(rows[i] + offset, transparent, outError) != TickType::kLayoutBounds) {
+                break;
+            }
+        }
+    }
+    return true;
+}
+
+static void findMaxOpacity(png_bytepp rows, int startX, int startY, int endX, int endY,
+                           int dX, int dY, int* outInset) {
+    uint8_t maxOpacity = 0;
+    int inset = 0;
+    *outInset = 0;
+    for (int x = startX, y = startY; x != endX && y != endY; x += dX, y += dY, inset++) {
+        png_byte* color = rows[y] + x * 4;
+        uint8_t opacity = color[3];
+        if (opacity > maxOpacity) {
+            maxOpacity = opacity;
+            *outInset = inset;
+        }
+        if (opacity == 0xff) return;
+    }
+}
+
+static uint8_t maxAlphaOverRow(png_bytep row, int startX, int endX) {
+    uint8_t maxAlpha = 0;
+    for (int x = startX; x < endX; x++) {
+        uint8_t alpha = (row + x * 4)[3];
+        if (alpha > maxAlpha) maxAlpha = alpha;
+    }
+    return maxAlpha;
+}
+
+static uint8_t maxAlphaOverCol(png_bytepp rows, int offsetX, int startY, int endY) {
+    uint8_t maxAlpha = 0;
+    for (int y = startY; y < endY; y++) {
+        uint8_t alpha = (rows[y] + offsetX * 4)[3];
+        if (alpha > maxAlpha) maxAlpha = alpha;
+    }
+    return maxAlpha;
+}
+
+static void getOutline(PngInfo* image) {
+    int midX = image->width / 2;
+    int midY = image->height / 2;
+    int endX = image->width - 2;
+    int endY = image->height - 2;
+
+    // find left and right extent of nine patch content on center row
+    if (image->width > 4) {
+        findMaxOpacity(image->rows.data(), 1, midY, midX, -1, 1, 0, &image->outlineInsetsLeft);
+        findMaxOpacity(image->rows.data(), endX, midY, midX, -1, -1, 0,
+                       &image->outlineInsetsRight);
+    } else {
+        image->outlineInsetsLeft = 0;
+        image->outlineInsetsRight = 0;
+    }
+
+    // find top and bottom extent of nine patch content on center column
+    if (image->height > 4) {
+        findMaxOpacity(image->rows.data(), midX, 1, -1, midY, 0, 1, &image->outlineInsetsTop);
+        findMaxOpacity(image->rows.data(), midX, endY, -1, midY, 0, -1,
+                       &image->outlineInsetsBottom);
+    } else {
+        image->outlineInsetsTop = 0;
+        image->outlineInsetsBottom = 0;
+    }
+
+    int innerStartX = 1 + image->outlineInsetsLeft;
+    int innerStartY = 1 + image->outlineInsetsTop;
+    int innerEndX = endX - image->outlineInsetsRight;
+    int innerEndY = endY - image->outlineInsetsBottom;
+    int innerMidX = (innerEndX + innerStartX) / 2;
+    int innerMidY = (innerEndY + innerStartY) / 2;
+
+    // assuming the image is a round rect, compute the radius by marching
+    // diagonally from the top left corner towards the center
+    image->outlineAlpha = std::max(
+            maxAlphaOverRow(image->rows[innerMidY], innerStartX, innerEndX),
+            maxAlphaOverCol(image->rows.data(), innerMidX, innerStartY, innerStartY));
+
+    int diagonalInset = 0;
+    findMaxOpacity(image->rows.data(), innerStartX, innerStartY, innerMidX, innerMidY, 1, 1,
+                   &diagonalInset);
+
+    /* Determine source radius based upon inset:
+     *     sqrt(r^2 + r^2) = sqrt(i^2 + i^2) + r
+     *     sqrt(2) * r = sqrt(2) * i + r
+     *     (sqrt(2) - 1) * r = sqrt(2) * i
+     *     r = sqrt(2) / (sqrt(2) - 1) * i
+     */
+    image->outlineRadius = 3.4142f * diagonalInset;
+
+    if (kDebug) {
+        printf("outline insets %d %d %d %d, rad %f, alpha %x\n",
+                image->outlineInsetsLeft,
+                image->outlineInsetsTop,
+                image->outlineInsetsRight,
+                image->outlineInsetsBottom,
+                image->outlineRadius,
+                image->outlineAlpha);
+    }
+}
+
+static uint32_t getColor(png_bytepp rows, int left, int top, int right, int bottom) {
+    png_bytep color = rows[top] + left*4;
+
+    if (left > right || top > bottom) {
+        return android::Res_png_9patch::TRANSPARENT_COLOR;
+    }
+
+    while (top <= bottom) {
+        for (int i = left; i <= right; i++) {
+            png_bytep p = rows[top]+i*4;
+            if (color[3] == 0) {
+                if (p[3] != 0) {
+                    return android::Res_png_9patch::NO_COLOR;
+                }
+            } else if (p[0] != color[0] || p[1] != color[1] ||
+                    p[2] != color[2] || p[3] != color[3]) {
+                return android::Res_png_9patch::NO_COLOR;
+            }
+        }
+        top++;
+    }
+
+    if (color[3] == 0) {
+        return android::Res_png_9patch::TRANSPARENT_COLOR;
+    }
+    return (color[3]<<24) | (color[0]<<16) | (color[1]<<8) | color[2];
+}
+
+static bool do9Patch(PngInfo* image, std::string* outError) {
+    image->is9Patch = true;
+
+    int W = image->width;
+    int H = image->height;
+    int i, j;
+
+    const int maxSizeXDivs = W * sizeof(int32_t);
+    const int maxSizeYDivs = H * sizeof(int32_t);
+    int32_t* xDivs = image->xDivs = new int32_t[W];
+    int32_t* yDivs = image->yDivs = new int32_t[H];
+    uint8_t numXDivs = 0;
+    uint8_t numYDivs = 0;
+
+    int8_t numColors;
+    int numRows;
+    int numCols;
+    int top;
+    int left;
+    int right;
+    int bottom;
+    memset(xDivs, -1, maxSizeXDivs);
+    memset(yDivs, -1, maxSizeYDivs);
+    image->info9Patch.paddingLeft = image->info9Patch.paddingRight = -1;
+    image->info9Patch.paddingTop = image->info9Patch.paddingBottom = -1;
+    image->layoutBoundsLeft = image->layoutBoundsRight = 0;
+    image->layoutBoundsTop = image->layoutBoundsBottom = 0;
+
+    png_bytep p = image->rows[0];
+    bool transparent = p[3] == 0;
+    bool hasColor = false;
+
+    const char* errorMsg = nullptr;
+    int errorPixel = -1;
+    const char* errorEdge = nullptr;
+
+    int colorIndex = 0;
+    std::vector<png_bytep> newRows;
+
+    // Validate size...
+    if (W < 3 || H < 3) {
+        errorMsg = "Image must be at least 3x3 (1x1 without frame) pixels";
+        goto getout;
+    }
+
+    // Validate frame...
+    if (!transparent &&
+            (p[0] != 0xFF || p[1] != 0xFF || p[2] != 0xFF || p[3] != 0xFF)) {
+        errorMsg = "Must have one-pixel frame that is either transparent or white";
+        goto getout;
+    }
+
+    // Find left and right of sizing areas...
+    if (!getHorizontalTicks(p, W, transparent, true, &xDivs[0], &xDivs[1], &errorMsg, &numXDivs,
+                            true)) {
+        errorPixel = xDivs[0];
+        errorEdge = "top";
+        goto getout;
+    }
+
+    // Find top and bottom of sizing areas...
+    if (!getVerticalTicks(image->rows.data(), 0, H, transparent, true, &yDivs[0], &yDivs[1],
+                          &errorMsg, &numYDivs, true)) {
+        errorPixel = yDivs[0];
+        errorEdge = "left";
+        goto getout;
+    }
+
+    // Copy patch size data into image...
+    image->info9Patch.numXDivs = numXDivs;
+    image->info9Patch.numYDivs = numYDivs;
+
+    // Find left and right of padding area...
+    if (!getHorizontalTicks(image->rows[H-1], W, transparent, false,
+                            &image->info9Patch.paddingLeft, &image->info9Patch.paddingRight,
+                            &errorMsg, nullptr, false)) {
+        errorPixel = image->info9Patch.paddingLeft;
+        errorEdge = "bottom";
+        goto getout;
+    }
+
+    // Find top and bottom of padding area...
+    if (!getVerticalTicks(image->rows.data(), (W-1)*4, H, transparent, false,
+                          &image->info9Patch.paddingTop, &image->info9Patch.paddingBottom,
+                          &errorMsg, nullptr, false)) {
+        errorPixel = image->info9Patch.paddingTop;
+        errorEdge = "right";
+        goto getout;
+    }
+
+    // Find left and right of layout padding...
+    getHorizontalLayoutBoundsTicks(image->rows[H-1], W, transparent, false,
+                                   &image->layoutBoundsLeft, &image->layoutBoundsRight, &errorMsg);
+
+    getVerticalLayoutBoundsTicks(image->rows.data(), (W-1)*4, H, transparent, false,
+                                 &image->layoutBoundsTop, &image->layoutBoundsBottom, &errorMsg);
+
+    image->haveLayoutBounds = image->layoutBoundsLeft != 0
+                               || image->layoutBoundsRight != 0
+                               || image->layoutBoundsTop != 0
+                               || image->layoutBoundsBottom != 0;
+
+    if (image->haveLayoutBounds) {
+        if (kDebug) {
+            printf("layoutBounds=%d %d %d %d\n", image->layoutBoundsLeft, image->layoutBoundsTop,
+                    image->layoutBoundsRight, image->layoutBoundsBottom);
+        }
+    }
+
+    // use opacity of pixels to estimate the round rect outline
+    getOutline(image);
+
+    // If padding is not yet specified, take values from size.
+    if (image->info9Patch.paddingLeft < 0) {
+        image->info9Patch.paddingLeft = xDivs[0];
+        image->info9Patch.paddingRight = W - 2 - xDivs[1];
+    } else {
+        // Adjust value to be correct!
+        image->info9Patch.paddingRight = W - 2 - image->info9Patch.paddingRight;
+    }
+    if (image->info9Patch.paddingTop < 0) {
+        image->info9Patch.paddingTop = yDivs[0];
+        image->info9Patch.paddingBottom = H - 2 - yDivs[1];
+    } else {
+        // Adjust value to be correct!
+        image->info9Patch.paddingBottom = H - 2 - image->info9Patch.paddingBottom;
+    }
+
+/*    if (kDebug) {
+        printf("Size ticks for %s: x0=%d, x1=%d, y0=%d, y1=%d\n", imageName,
+                xDivs[0], xDivs[1],
+                yDivs[0], yDivs[1]);
+        printf("padding ticks for %s: l=%d, r=%d, t=%d, b=%d\n", imageName,
+                image->info9Patch.paddingLeft, image->info9Patch.paddingRight,
+                image->info9Patch.paddingTop, image->info9Patch.paddingBottom);
+    }*/
+
+    // Remove frame from image.
+    newRows.resize(H - 2);
+    for (i = 0; i < H - 2; i++) {
+        newRows[i] = image->rows[i + 1];
+        memmove(newRows[i], newRows[i] + 4, (W - 2) * 4);
+    }
+    image->rows.swap(newRows);
+
+    image->width -= 2;
+    W = image->width;
+    image->height -= 2;
+    H = image->height;
+
+    // Figure out the number of rows and columns in the N-patch
+    numCols = numXDivs + 1;
+    if (xDivs[0] == 0) {  // Column 1 is strechable
+        numCols--;
+    }
+    if (xDivs[numXDivs - 1] == W) {
+        numCols--;
+    }
+    numRows = numYDivs + 1;
+    if (yDivs[0] == 0) {  // Row 1 is strechable
+        numRows--;
+    }
+    if (yDivs[numYDivs - 1] == H) {
+        numRows--;
+    }
+
+    // Make sure the amount of rows and columns will fit in the number of
+    // colors we can use in the 9-patch format.
+    if (numRows * numCols > 0x7F) {
+        errorMsg = "Too many rows and columns in 9-patch perimeter";
+        goto getout;
+    }
+
+    numColors = numRows * numCols;
+    image->info9Patch.numColors = numColors;
+    image->colors.resize(numColors);
+
+    // Fill in color information for each patch.
+
+    uint32_t c;
+    top = 0;
+
+    // The first row always starts with the top being at y=0 and the bottom
+    // being either yDivs[1] (if yDivs[0]=0) of yDivs[0].  In the former case
+    // the first row is stretchable along the Y axis, otherwise it is fixed.
+    // The last row always ends with the bottom being bitmap.height and the top
+    // being either yDivs[numYDivs-2] (if yDivs[numYDivs-1]=bitmap.height) or
+    // yDivs[numYDivs-1]. In the former case the last row is stretchable along
+    // the Y axis, otherwise it is fixed.
+    //
+    // The first and last columns are similarly treated with respect to the X
+    // axis.
+    //
+    // The above is to help explain some of the special casing that goes on the
+    // code below.
+
+    // The initial yDiv and whether the first row is considered stretchable or
+    // not depends on whether yDiv[0] was zero or not.
+    for (j = (yDivs[0] == 0 ? 1 : 0); j <= numYDivs && top < H; j++) {
+        if (j == numYDivs) {
+            bottom = H;
+        } else {
+            bottom = yDivs[j];
+        }
+        left = 0;
+        // The initial xDiv and whether the first column is considered
+        // stretchable or not depends on whether xDiv[0] was zero or not.
+        for (i = xDivs[0] == 0 ? 1 : 0; i <= numXDivs && left < W; i++) {
+            if (i == numXDivs) {
+                right = W;
+            } else {
+                right = xDivs[i];
+            }
+            c = getColor(image->rows.data(), left, top, right - 1, bottom - 1);
+            image->colors[colorIndex++] = c;
+            if (kDebug) {
+                if (c != android::Res_png_9patch::NO_COLOR) {
+                    hasColor = true;
+                }
+            }
+            left = right;
+        }
+        top = bottom;
+    }
+
+    assert(colorIndex == numColors);
+
+    if (kDebug && hasColor) {
+        for (i = 0; i < numColors; i++) {
+            if (i == 0) printf("Colors:\n");
+            printf(" #%08x", image->colors[i]);
+            if (i == numColors - 1) printf("\n");
+        }
+    }
+getout:
+    if (errorMsg) {
+        std::stringstream err;
+        err << "9-patch malformed: " << errorMsg;
+        if (!errorEdge) {
+            err << "." << std::endl;
+            if (errorPixel >= 0) {
+                err << "Found at pixel #" << errorPixel << " along " << errorEdge << " edge";
+            } else {
+                err << "Found along " << errorEdge << " edge";
+            }
+        }
+        *outError = err.str();
+        return false;
+    }
+    return true;
+}
+
+
+bool Png::process(const Source& source, std::istream& input, std::ostream& output,
+                  const Options& options, std::string* outError) {
+    png_byte signature[kPngSignatureSize];
+
+    // Read the PNG signature first.
+    if (!input.read(reinterpret_cast<char*>(signature), kPngSignatureSize)) {
+        *outError = strerror(errno);
+        return false;
+    }
+
+    // If the PNG signature doesn't match, bail early.
+    if (png_sig_cmp(signature, 0, kPngSignatureSize) != 0) {
+        *outError = "not a valid png file";
+        return false;
+    }
+
+    SourceLogger logger(source);
+    bool result = false;
+    png_structp readPtr = nullptr;
+    png_infop infoPtr = nullptr;
+    png_structp writePtr = nullptr;
+    png_infop writeInfoPtr = nullptr;
+    PngInfo pngInfo = {};
+
+    readPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
+    if (!readPtr) {
+        *outError = "failed to allocate read ptr";
+        goto bail;
+    }
+
+    infoPtr = png_create_info_struct(readPtr);
+    if (!infoPtr) {
+        *outError = "failed to allocate info ptr";
+        goto bail;
+    }
+
+    png_set_error_fn(readPtr, reinterpret_cast<png_voidp>(&logger), nullptr, logWarning);
+
+    // Set the read function to read from std::istream.
+    png_set_read_fn(readPtr, (png_voidp)&input, readDataFromStream);
+
+    if (!readPng(readPtr, infoPtr, &pngInfo, outError)) {
+        goto bail;
+    }
+
+    if (util::stringEndsWith<char>(source.path, ".9.png")) {
+        if (!do9Patch(&pngInfo, outError)) {
+            goto bail;
+        }
+    }
+
+    writePtr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, nullptr, nullptr);
+    if (!writePtr) {
+        *outError = "failed to allocate write ptr";
+        goto bail;
+    }
+
+    writeInfoPtr = png_create_info_struct(writePtr);
+    if (!writeInfoPtr) {
+        *outError = "failed to allocate write info ptr";
+        goto bail;
+    }
+
+    png_set_error_fn(writePtr, nullptr, nullptr, logWarning);
+
+    // Set the write function to write to std::ostream.
+    png_set_write_fn(writePtr, (png_voidp)&output, writeDataToStream, flushDataToStream);
+
+    if (!writePng(writePtr, writeInfoPtr, &pngInfo, options.grayScaleTolerance, &logger,
+                  outError)) {
+        goto bail;
+    }
+
+    result = true;
+bail:
+    if (readPtr) {
+        png_destroy_read_struct(&readPtr, &infoPtr, nullptr);
+    }
+
+    if (writePtr) {
+        png_destroy_write_struct(&writePtr, &writeInfoPtr);
+    }
+    return result;
+}
+
+} // namespace aapt
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/tools/aapt2/Png.h
similarity index 60%
copy from core/java/android/service/fingerprint/Fingerprint.aidl
copy to tools/aapt2/Png.h
index c9fd989..bc80754 100644
--- a/core/java/android/service/fingerprint/Fingerprint.aidl
+++ b/tools/aapt2/Png.h
@@ -13,7 +13,26 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.service.fingerprint;
 
-// @hide
-parcelable Fingerprint;
+#ifndef AAPT_PNG_H
+#define AAPT_PNG_H
+
+#include "Source.h"
+
+#include <iostream>
+#include <string>
+
+namespace aapt {
+
+struct Png {
+    struct Options {
+        int grayScaleTolerance = 0;
+    };
+
+    bool process(const Source& source, std::istream& input, std::ostream& output,
+                 const Options& options, std::string* outError);
+};
+
+} // namespace aapt
+
+#endif // AAPT_PNG_H
diff --git a/tools/aapt2/ResChunkPullParser.cpp b/tools/aapt2/ResChunkPullParser.cpp
new file mode 100644
index 0000000..78ea60e
--- /dev/null
+++ b/tools/aapt2/ResChunkPullParser.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResChunkPullParser.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <cstddef>
+
+namespace aapt {
+
+using android::ResChunk_header;
+
+ResChunkPullParser::Event ResChunkPullParser::next() {
+    if (!isGoodEvent(mEvent)) {
+        return mEvent;
+    }
+
+    if (mEvent == Event::StartDocument) {
+        mCurrentChunk = mData;
+    } else {
+        mCurrentChunk = reinterpret_cast<const ResChunk_header*>(
+                reinterpret_cast<const char*>(mCurrentChunk) + mCurrentChunk->size);
+    }
+
+    const std::ptrdiff_t diff = reinterpret_cast<const char*>(mCurrentChunk)
+            - reinterpret_cast<const char*>(mData);
+    assert(diff >= 0 && "diff is negative");
+    const size_t offset = static_cast<const size_t>(diff);
+
+    if (offset == mLen) {
+        mCurrentChunk = nullptr;
+        return (mEvent = Event::EndDocument);
+    } else if (offset + sizeof(ResChunk_header) > mLen) {
+        mLastError = "chunk is past the end of the document";
+        mCurrentChunk = nullptr;
+        return (mEvent = Event::BadDocument);
+    }
+
+    if (mCurrentChunk->headerSize < sizeof(ResChunk_header)) {
+        mLastError = "chunk has too small header";
+        mCurrentChunk = nullptr;
+        return (mEvent = Event::BadDocument);
+    } else if (mCurrentChunk->size < mCurrentChunk->headerSize) {
+        mLastError = "chunk's total size is smaller than header";
+        mCurrentChunk = nullptr;
+        return (mEvent = Event::BadDocument);
+    } else if (offset + mCurrentChunk->size > mLen) {
+        mLastError = "chunk's data extends past the end of the document";
+        mCurrentChunk = nullptr;
+        return (mEvent = Event::BadDocument);
+    }
+    return (mEvent = Event::Chunk);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ResChunkPullParser.h b/tools/aapt2/ResChunkPullParser.h
new file mode 100644
index 0000000..7366c89
--- /dev/null
+++ b/tools/aapt2/ResChunkPullParser.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RES_CHUNK_PULL_PARSER_H
+#define AAPT_RES_CHUNK_PULL_PARSER_H
+
+#include <androidfw/ResourceTypes.h>
+#include <string>
+
+namespace aapt {
+
+/**
+ * A pull parser, modeled after XmlPullParser, that reads
+ * android::ResChunk_header structs from a block of data.
+ *
+ * An android::ResChunk_header specifies a type, headerSize,
+ * and size. The pull parser will verify that the chunk's size
+ * doesn't extend beyond the available data, and will iterate
+ * over each chunk in the given block of data.
+ *
+ * Processing nested chunks is done by creating a new ResChunkPullParser
+ * pointing to the data portion of a chunk.
+ */
+class ResChunkPullParser {
+public:
+    enum class Event {
+        StartDocument,
+        EndDocument,
+        BadDocument,
+
+        Chunk,
+    };
+
+    /**
+     * Returns false if the event is EndDocument or BadDocument.
+     */
+    static bool isGoodEvent(Event event);
+
+    /**
+     * Create a ResChunkPullParser to read android::ResChunk_headers
+     * from the memory pointed to by data, of len bytes.
+     */
+    ResChunkPullParser(const void* data, size_t len);
+
+    ResChunkPullParser(const ResChunkPullParser&) = delete;
+
+    Event getEvent() const;
+    const std::string& getLastError() const;
+    const android::ResChunk_header* getChunk() const;
+
+    /**
+     * Move to the next android::ResChunk_header.
+     */
+    Event next();
+
+private:
+    Event mEvent;
+    const android::ResChunk_header* mData;
+    size_t mLen;
+    const android::ResChunk_header* mCurrentChunk;
+    std::string mLastError;
+};
+
+//
+// Implementation
+//
+
+inline bool ResChunkPullParser::isGoodEvent(ResChunkPullParser::Event event) {
+    return event != Event::EndDocument && event != Event::BadDocument;
+}
+
+inline ResChunkPullParser::ResChunkPullParser(const void* data, size_t len) :
+        mEvent(Event::StartDocument),
+        mData(reinterpret_cast<const android::ResChunk_header*>(data)),
+        mLen(len),
+        mCurrentChunk(nullptr) {
+}
+
+inline ResChunkPullParser::Event ResChunkPullParser::getEvent() const {
+    return mEvent;
+}
+
+inline const std::string& ResChunkPullParser::getLastError() const {
+    return mLastError;
+}
+
+inline const android::ResChunk_header* ResChunkPullParser::getChunk() const {
+    return mCurrentChunk;
+}
+
+} // namespace aapt
+
+#endif // AAPT_RES_CHUNK_PULL_PARSER_H
diff --git a/tools/aapt2/Resolver.cpp b/tools/aapt2/Resolver.cpp
new file mode 100644
index 0000000..93b5e98
--- /dev/null
+++ b/tools/aapt2/Resolver.cpp
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Maybe.h"
+#include "Resolver.h"
+#include "Resource.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <memory>
+#include <vector>
+
+namespace aapt {
+
+Resolver::Resolver(std::shared_ptr<const ResourceTable> table,
+                   std::shared_ptr<const android::AssetManager> sources) :
+        mTable(table), mSources(sources) {
+}
+
+Maybe<ResourceId> Resolver::findId(const ResourceName& name) {
+    Maybe<Entry> result = findAttribute(name);
+    if (result) {
+        return result.value().id;
+    }
+    return {};
+}
+
+Maybe<Resolver::Entry> Resolver::findAttribute(const ResourceName& name) {
+    auto cacheIter = mCache.find(name);
+    if (cacheIter != std::end(mCache)) {
+        return Entry{ cacheIter->second.id, cacheIter->second.attr.get() };
+    }
+
+    const ResourceTableType* type;
+    const ResourceEntry* entry;
+    std::tie(type, entry) = mTable->findResource(name);
+    if (type && entry) {
+        Entry result = {};
+        if (mTable->getPackageId() != ResourceTable::kUnsetPackageId &&
+                type->typeId != ResourceTableType::kUnsetTypeId &&
+                entry->entryId != ResourceEntry::kUnsetEntryId) {
+            result.id = ResourceId(mTable->getPackageId(), type->typeId, entry->entryId);
+        }
+
+        if (!entry->values.empty()) {
+            visitFunc<Attribute>(*entry->values.front().value, [&result](Attribute& attr) {
+                    result.attr = &attr;
+            });
+        }
+        return result;
+    }
+
+    const CacheEntry* cacheEntry = buildCacheEntry(name);
+    if (cacheEntry) {
+        return Entry{ cacheEntry->id, cacheEntry->attr.get() };
+    }
+    return {};
+}
+
+/**
+ * This is called when we need to lookup a resource name in the AssetManager.
+ * Since the values in the AssetManager are not parsed like in a ResourceTable,
+ * we must create Attribute objects here if we find them.
+ */
+const Resolver::CacheEntry* Resolver::buildCacheEntry(const ResourceName& name) {
+    const android::ResTable& table = mSources->getResources(false);
+
+    const StringPiece16 type16 = toString(name.type);
+    ResourceId resId {
+        table.identifierForName(
+                name.entry.data(), name.entry.size(),
+                type16.data(), type16.size(),
+                name.package.data(), name.package.size())
+    };
+
+    if (!resId.isValid()) {
+        return nullptr;
+    }
+
+    CacheEntry& entry = mCache[name];
+    entry.id = resId;
+
+    //
+    // Now check to see if this resource is an Attribute.
+    //
+
+    const android::ResTable::bag_entry* bagBegin;
+    ssize_t bags = table.lockBag(resId.id, &bagBegin);
+    if (bags < 1) {
+        table.unlockBag(bagBegin);
+        return &entry;
+    }
+
+    // Look for the ATTR_TYPE key in the bag and check the types it supports.
+    uint32_t attrTypeMask = 0;
+    for (ssize_t i = 0; i < bags; i++) {
+        if (bagBegin[i].map.name.ident == android::ResTable_map::ATTR_TYPE) {
+            attrTypeMask = bagBegin[i].map.value.data;
+        }
+    }
+
+    entry.attr = util::make_unique<Attribute>(false);
+
+    if (attrTypeMask & android::ResTable_map::TYPE_ENUM ||
+            attrTypeMask & android::ResTable_map::TYPE_FLAGS) {
+        for (ssize_t i = 0; i < bags; i++) {
+            if (Res_INTERNALID(bagBegin[i].map.name.ident)) {
+                // Internal IDs are special keys, which are not enum/flag symbols, so skip.
+                continue;
+            }
+
+            android::ResTable::resource_name symbolName;
+            bool result = table.getResourceName(bagBegin[i].map.name.ident, false,
+                    &symbolName);
+            assert(result);
+            const ResourceType* type = parseResourceType(
+                    StringPiece16(symbolName.type, symbolName.typeLen));
+            assert(type);
+
+            entry.attr->symbols.push_back(Attribute::Symbol{
+                    Reference(ResourceNameRef(
+                                StringPiece16(symbolName.package, symbolName.packageLen),
+                                *type,
+                                StringPiece16(symbolName.name, symbolName.nameLen))),
+                            bagBegin[i].map.value.data
+            });
+        }
+    }
+
+    entry.attr->typeMask |= attrTypeMask;
+    table.unlockBag(bagBegin);
+    return &entry;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Resolver.h b/tools/aapt2/Resolver.h
new file mode 100644
index 0000000..90a8cd9
--- /dev/null
+++ b/tools/aapt2/Resolver.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RESOLVER_H
+#define AAPT_RESOLVER_H
+
+#include "Maybe.h"
+#include "Resource.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <memory>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * Resolves symbolic references (package:type/entry) into resource IDs/objects.
+ * Encapsulates the search of library sources as well as the local ResourceTable.
+ */
+class Resolver {
+public:
+    /**
+     * Creates a resolver with a local ResourceTable and an AssetManager
+     * loaded with library packages.
+     */
+    Resolver(std::shared_ptr<const ResourceTable> table,
+             std::shared_ptr<const android::AssetManager> sources);
+
+    Resolver(const Resolver&) = delete; // Not copyable.
+
+    /**
+     * Holds the result of a resource name lookup.
+     */
+    struct Entry {
+        /**
+         * The ID of the resource. ResourceId::isValid() may
+         * return false if the resource has not been assigned
+         * an ID.
+         */
+        ResourceId id;
+
+        /**
+         * If the resource is an attribute, this will point
+         * to a valid Attribute object, or else it will be
+         * nullptr.
+         */
+        const Attribute* attr;
+    };
+
+    /**
+     * Return the package to use when none is specified. This
+     * is the package name of the app being built.
+     */
+    const std::u16string& getDefaultPackage() const;
+
+    /**
+     * Returns a ResourceID if the name is found. The ResourceID
+     * may not be valid if the resource was not assigned an ID.
+     */
+    Maybe<ResourceId> findId(const ResourceName& name);
+
+    /**
+     * Returns an Entry if the name is found. Entry::attr
+     * may be nullptr if the resource is not an attribute.
+     */
+    Maybe<Entry> findAttribute(const ResourceName& name);
+
+    const android::ResTable& getResTable() const;
+
+private:
+    struct CacheEntry {
+        ResourceId id;
+        std::unique_ptr<Attribute> attr;
+    };
+
+    const CacheEntry* buildCacheEntry(const ResourceName& name);
+
+    std::shared_ptr<const ResourceTable> mTable;
+    std::shared_ptr<const android::AssetManager> mSources;
+    std::map<ResourceName, CacheEntry> mCache;
+};
+
+inline const std::u16string& Resolver::getDefaultPackage() const {
+    return mTable->getPackage();
+}
+
+inline const android::ResTable& Resolver::getResTable() const {
+    return mSources->getResources(false);
+}
+
+} // namespace aapt
+
+#endif // AAPT_RESOLVER_H
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
new file mode 100644
index 0000000..287d8de
--- /dev/null
+++ b/tools/aapt2/Resource.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Resource.h"
+#include "StringPiece.h"
+
+#include <map>
+#include <string>
+
+namespace aapt {
+
+StringPiece16 toString(ResourceType type) {
+    switch (type) {
+        case ResourceType::kAnim:          return u"anim";
+        case ResourceType::kAnimator:      return u"animator";
+        case ResourceType::kArray:         return u"array";
+        case ResourceType::kAttr:          return u"attr";
+        case ResourceType::kAttrPrivate:   return u"attr";
+        case ResourceType::kBool:          return u"bool";
+        case ResourceType::kColor:         return u"color";
+        case ResourceType::kDimen:         return u"dimen";
+        case ResourceType::kDrawable:      return u"drawable";
+        case ResourceType::kFraction:      return u"fraction";
+        case ResourceType::kId:            return u"id";
+        case ResourceType::kInteger:       return u"integer";
+        case ResourceType::kIntegerArray:  return u"integer-array";
+        case ResourceType::kInterpolator:  return u"interpolator";
+        case ResourceType::kLayout:        return u"layout";
+        case ResourceType::kMenu:          return u"menu";
+        case ResourceType::kMipmap:        return u"mipmap";
+        case ResourceType::kPlurals:       return u"plurals";
+        case ResourceType::kRaw:           return u"raw";
+        case ResourceType::kString:        return u"string";
+        case ResourceType::kStyle:         return u"style";
+        case ResourceType::kStyleable:     return u"styleable";
+        case ResourceType::kTransition:    return u"transition";
+        case ResourceType::kXml:           return u"xml";
+    }
+    return {};
+}
+
+static const std::map<StringPiece16, ResourceType> sResourceTypeMap {
+        { u"anim", ResourceType::kAnim },
+        { u"animator", ResourceType::kAnimator },
+        { u"array", ResourceType::kArray },
+        { u"attr", ResourceType::kAttr },
+        { u"^attr-private", ResourceType::kAttrPrivate },
+        { u"bool", ResourceType::kBool },
+        { u"color", ResourceType::kColor },
+        { u"dimen", ResourceType::kDimen },
+        { u"drawable", ResourceType::kDrawable },
+        { u"fraction", ResourceType::kFraction },
+        { u"id", ResourceType::kId },
+        { u"integer", ResourceType::kInteger },
+        { u"integer-array", ResourceType::kIntegerArray },
+        { u"interpolator", ResourceType::kInterpolator },
+        { u"layout", ResourceType::kLayout },
+        { u"menu", ResourceType::kMenu },
+        { u"mipmap", ResourceType::kMipmap },
+        { u"plurals", ResourceType::kPlurals },
+        { u"raw", ResourceType::kRaw },
+        { u"string", ResourceType::kString },
+        { u"style", ResourceType::kStyle },
+        { u"styleable", ResourceType::kStyleable },
+        { u"transition", ResourceType::kTransition },
+        { u"xml", ResourceType::kXml },
+};
+
+const ResourceType* parseResourceType(const StringPiece16& str) {
+    auto iter = sResourceTypeMap.find(str);
+    if (iter == std::end(sResourceTypeMap)) {
+        return nullptr;
+    }
+    return &iter->second;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
new file mode 100644
index 0000000..4d2c64c
--- /dev/null
+++ b/tools/aapt2/Resource.h
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RESOURCE_H
+#define AAPT_RESOURCE_H
+
+#include "StringPiece.h"
+
+#include <iomanip>
+#include <limits>
+#include <string>
+#include <tuple>
+
+namespace aapt {
+
+/**
+ * The various types of resource types available. Corresponds
+ * to the 'type' in package:type/entry.
+ */
+enum class ResourceType {
+    kAnim,
+    kAnimator,
+    kArray,
+    kAttr,
+    kAttrPrivate,
+    kBool,
+    kColor,
+    kDimen,
+    kDrawable,
+    kFraction,
+    kId,
+    kInteger,
+    kIntegerArray,
+    kInterpolator,
+    kLayout,
+    kMenu,
+    kMipmap,
+    kPlurals,
+    kRaw,
+    kString,
+    kStyle,
+    kStyleable,
+    kTransition,
+    kXml,
+};
+
+StringPiece16 toString(ResourceType type);
+
+/**
+ * Returns a pointer to a valid ResourceType, or nullptr if
+ * the string was invalid.
+ */
+const ResourceType* parseResourceType(const StringPiece16& str);
+
+/**
+ * A resource's name. This can uniquely identify
+ * a resource in the ResourceTable.
+ */
+struct ResourceName {
+    std::u16string package;
+    ResourceType type;
+    std::u16string entry;
+
+    bool isValid() const;
+    bool operator<(const ResourceName& rhs) const;
+    bool operator==(const ResourceName& rhs) const;
+    bool operator!=(const ResourceName& rhs) const;
+};
+
+/**
+ * Same as ResourceName, but uses StringPieces instead.
+ * Use this if you need to avoid copying and know that
+ * the lifetime of this object is shorter than that
+ * of the original string.
+ */
+struct ResourceNameRef {
+    StringPiece16 package;
+    ResourceType type;
+    StringPiece16 entry;
+
+    ResourceNameRef() = default;
+    ResourceNameRef(const ResourceNameRef&) = default;
+    ResourceNameRef(ResourceNameRef&&) = default;
+    ResourceNameRef(const ResourceName& rhs);
+    ResourceNameRef(const StringPiece16& p, ResourceType t, const StringPiece16& e);
+    ResourceNameRef& operator=(const ResourceName& rhs);
+
+    ResourceName toResourceName() const;
+    bool isValid() const;
+
+    bool operator<(const ResourceNameRef& rhs) const;
+    bool operator==(const ResourceNameRef& rhs) const;
+    bool operator!=(const ResourceNameRef& rhs) const;
+};
+
+/**
+ * A binary identifier representing a resource. Internally it
+ * is a 32bit integer split as follows:
+ *
+ * 0xPPTTEEEE
+ *
+ * PP: 8 bit package identifier. 0x01 is reserved for system
+ *     and 0x7f is reserved for the running app.
+ * TT: 8 bit type identifier. 0x00 is invalid.
+ * EEEE: 16 bit entry identifier.
+ */
+struct ResourceId {
+    uint32_t id;
+
+    ResourceId();
+    ResourceId(const ResourceId& rhs);
+    ResourceId(uint32_t resId);
+    ResourceId(size_t p, size_t t, size_t e);
+
+    bool isValid() const;
+    uint8_t packageId() const;
+    uint8_t typeId() const;
+    uint16_t entryId() const;
+    bool operator<(const ResourceId& rhs) const;
+};
+
+//
+// ResourceId implementation.
+//
+
+inline ResourceId::ResourceId() : id(0) {
+}
+
+inline ResourceId::ResourceId(const ResourceId& rhs) : id(rhs.id) {
+}
+
+inline ResourceId::ResourceId(uint32_t resId) : id(resId) {
+}
+
+inline ResourceId::ResourceId(size_t p, size_t t, size_t e) : id(0) {
+    if (p > std::numeric_limits<uint8_t>::max() ||
+            t > std::numeric_limits<uint8_t>::max() ||
+            e > std::numeric_limits<uint16_t>::max()) {
+        // This will leave the ResourceId in an invalid state.
+        return;
+    }
+
+    id = (static_cast<uint8_t>(p) << 24) |
+         (static_cast<uint8_t>(t) << 16) |
+         static_cast<uint16_t>(e);
+}
+
+inline bool ResourceId::isValid() const {
+    return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
+}
+
+inline uint8_t ResourceId::packageId() const {
+    return static_cast<uint8_t>(id >> 24);
+}
+
+inline uint8_t ResourceId::typeId() const {
+    return static_cast<uint8_t>(id >> 16);
+}
+
+inline uint16_t ResourceId::entryId() const {
+    return static_cast<uint16_t>(id);
+}
+
+inline bool ResourceId::operator<(const ResourceId& rhs) const {
+    return id < rhs.id;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out,
+        const ResourceId& resId) {
+    std::ios_base::fmtflags oldFlags = out.flags();
+    char oldFill = out.fill();
+    out << "0x" << std::internal << std::setfill('0') << std::setw(8)
+        << std::hex << resId.id;
+    out.flags(oldFlags);
+    out.fill(oldFill);
+    return out;
+}
+
+//
+// ResourceType implementation.
+//
+
+inline ::std::ostream& operator<<(::std::ostream& out,
+        const ResourceType& val) {
+    return out << toString(val);
+}
+
+//
+// ResourceName implementation.
+//
+
+inline bool ResourceName::isValid() const {
+    return !package.empty() && !entry.empty();
+}
+
+inline bool ResourceName::operator<(const ResourceName& rhs) const {
+    return std::tie(package, type, entry)
+            < std::tie(rhs.package, rhs.type, rhs.entry);
+}
+
+inline bool ResourceName::operator==(const ResourceName& rhs) const {
+    return std::tie(package, type, entry)
+            == std::tie(rhs.package, rhs.type, rhs.entry);
+}
+
+inline bool ResourceName::operator!=(const ResourceName& rhs) const {
+    return std::tie(package, type, entry)
+            != std::tie(rhs.package, rhs.type, rhs.entry);
+}
+
+//
+// ResourceNameRef implementation.
+//
+
+inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs) :
+        package(rhs.package), type(rhs.type), entry(rhs.entry) {
+}
+
+inline ResourceNameRef::ResourceNameRef(const StringPiece16& p, ResourceType t,
+                                        const StringPiece16& e) :
+        package(p), type(t), entry(e) {
+}
+
+inline ResourceNameRef& ResourceNameRef::operator=(const ResourceName& rhs) {
+    package = rhs.package;
+    type = rhs.type;
+    entry = rhs.entry;
+    return *this;
+}
+
+inline ResourceName ResourceNameRef::toResourceName() const {
+    return { package.toString(), type, entry.toString() };
+}
+
+inline bool ResourceNameRef::isValid() const {
+    return !package.empty() && !entry.empty();
+}
+
+inline bool ResourceNameRef::operator<(const ResourceNameRef& rhs) const {
+    return std::tie(package, type, entry)
+            < std::tie(rhs.package, rhs.type, rhs.entry);
+}
+
+inline bool ResourceNameRef::operator==(const ResourceNameRef& rhs) const {
+    return std::tie(package, type, entry)
+            == std::tie(rhs.package, rhs.type, rhs.entry);
+}
+
+inline bool ResourceNameRef::operator!=(const ResourceNameRef& rhs) const {
+    return std::tie(package, type, entry)
+            != std::tie(rhs.package, rhs.type, rhs.entry);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out,
+        const ResourceNameRef& name) {
+    if (!name.package.empty()) {
+        out << name.package << ":";
+    }
+    return out << name.type << "/" << name.entry;
+}
+
+} // namespace aapt
+
+#endif // AAPT_RESOURCE_H
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
new file mode 100644
index 0000000..4c96187
--- /dev/null
+++ b/tools/aapt2/ResourceParser.cpp
@@ -0,0 +1,1317 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Logger.h"
+#include "ResourceParser.h"
+#include "ResourceValues.h"
+#include "ScopedXmlPullParser.h"
+#include "SourceXmlPullParser.h"
+#include "Util.h"
+#include "XliffXmlPullParser.h"
+
+namespace aapt {
+
+void ResourceParser::extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
+                                         StringPiece16* outType, StringPiece16* outEntry) {
+    const char16_t* start = str.data();
+    const char16_t* end = start + str.size();
+    const char16_t* current = start;
+    while (current != end) {
+        if (outType->size() == 0 && *current == u'/') {
+            outType->assign(start, current - start);
+            start = current + 1;
+        } else if (outPackage->size() == 0 && *current == u':') {
+            outPackage->assign(start, current - start);
+            start = current + 1;
+        }
+        current++;
+    }
+    outEntry->assign(start, end - start);
+}
+
+bool ResourceParser::tryParseReference(const StringPiece16& str, ResourceNameRef* outRef,
+                                       bool* outCreate, bool* outPrivate) {
+    StringPiece16 trimmedStr(util::trimWhitespace(str));
+    if (trimmedStr.empty()) {
+        return false;
+    }
+
+    if (trimmedStr.data()[0] == u'@') {
+        size_t offset = 1;
+        *outCreate = false;
+        if (trimmedStr.data()[1] == u'+') {
+            *outCreate = true;
+            offset += 1;
+        } else if (trimmedStr.data()[1] == u'*') {
+            *outPrivate = true;
+            offset += 1;
+        }
+        StringPiece16 package;
+        StringPiece16 type;
+        StringPiece16 entry;
+        extractResourceName(trimmedStr.substr(offset, trimmedStr.size() - offset),
+                            &package, &type, &entry);
+
+        const ResourceType* parsedType = parseResourceType(type);
+        if (!parsedType) {
+            return false;
+        }
+
+        if (*outCreate && *parsedType != ResourceType::kId) {
+            return false;
+        }
+
+        outRef->package = package;
+        outRef->type = *parsedType;
+        outRef->entry = entry;
+        return true;
+    }
+    return false;
+}
+
+bool ResourceParser::tryParseAttributeReference(const StringPiece16& str,
+                                                ResourceNameRef* outRef) {
+    StringPiece16 trimmedStr(util::trimWhitespace(str));
+    if (trimmedStr.empty()) {
+        return false;
+    }
+
+    if (*trimmedStr.data() == u'?') {
+        StringPiece16 package;
+        StringPiece16 type;
+        StringPiece16 entry;
+        extractResourceName(trimmedStr.substr(1, trimmedStr.size() - 1), &package, &type, &entry);
+
+        if (!type.empty() && type != u"attr") {
+            return false;
+        }
+
+        outRef->package = package;
+        outRef->type = ResourceType::kAttr;
+        outRef->entry = entry;
+        return true;
+    }
+    return false;
+}
+
+std::unique_ptr<Reference> ResourceParser::tryParseReference(const StringPiece16& str,
+                                                             const StringPiece16& defaultPackage,
+                                                             bool* outCreate) {
+    ResourceNameRef ref;
+    bool privateRef = false;
+    if (tryParseReference(str, &ref, outCreate, &privateRef)) {
+        if (ref.package.empty()) {
+            ref.package = defaultPackage;
+        }
+        std::unique_ptr<Reference> value = util::make_unique<Reference>(ref);
+        value->privateReference = privateRef;
+        return value;
+    }
+
+    if (tryParseAttributeReference(str, &ref)) {
+        if (ref.package.empty()) {
+            ref.package = defaultPackage;
+        }
+        *outCreate = false;
+        return util::make_unique<Reference>(ref, Reference::Type::kAttribute);
+    }
+    return {};
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseNullOrEmpty(const StringPiece16& str) {
+    StringPiece16 trimmedStr(util::trimWhitespace(str));
+    uint32_t data = 0;
+    if (trimmedStr == u"@null") {
+        data = android::Res_value::DATA_NULL_UNDEFINED;
+    } else if (trimmedStr == u"@empty") {
+        data = android::Res_value::DATA_NULL_EMPTY;
+    } else {
+        return {};
+    }
+
+    android::Res_value value = {};
+    value.dataType = android::Res_value::TYPE_NULL;
+    value.data = data;
+    return util::make_unique<BinaryPrimitive>(value);
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseEnumSymbol(const Attribute& enumAttr,
+                                                                    const StringPiece16& str) {
+    StringPiece16 trimmedStr(util::trimWhitespace(str));
+    for (const auto& entry : enumAttr.symbols) {
+        // Enum symbols are stored as @package:id/symbol resources,
+        // so we need to match against the 'entry' part of the identifier.
+        const ResourceName& enumSymbolResourceName = entry.symbol.name;
+        if (trimmedStr == enumSymbolResourceName.entry) {
+            android::Res_value value = {};
+            value.dataType = android::Res_value::TYPE_INT_DEC;
+            value.data = entry.value;
+            return util::make_unique<BinaryPrimitive>(value);
+        }
+    }
+    return {};
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseFlagSymbol(const Attribute& flagAttr,
+                                                                    const StringPiece16& str) {
+    android::Res_value flags = {};
+    flags.dataType = android::Res_value::TYPE_INT_DEC;
+
+    for (StringPiece16 part : util::tokenize(str, u'|')) {
+        StringPiece16 trimmedPart = util::trimWhitespace(part);
+
+        bool flagSet = false;
+        for (const auto& entry : flagAttr.symbols) {
+            // Flag symbols are stored as @package:id/symbol resources,
+            // so we need to match against the 'entry' part of the identifier.
+            const ResourceName& flagSymbolResourceName = entry.symbol.name;
+            if (trimmedPart == flagSymbolResourceName.entry) {
+                flags.data |= entry.value;
+                flagSet = true;
+                break;
+            }
+        }
+
+        if (!flagSet) {
+            return {};
+        }
+    }
+    return util::make_unique<BinaryPrimitive>(flags);
+}
+
+static uint32_t parseHex(char16_t c, bool* outError) {
+   if (c >= u'0' && c <= u'9') {
+        return c - u'0';
+    } else if (c >= u'a' && c <= u'f') {
+        return c - u'a' + 0xa;
+    } else if (c >= u'A' && c <= u'F') {
+        return c - u'A' + 0xa;
+    } else {
+        *outError = true;
+        return 0xffffffffu;
+    }
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseColor(const StringPiece16& str) {
+    StringPiece16 colorStr(util::trimWhitespace(str));
+    const char16_t* start = colorStr.data();
+    const size_t len = colorStr.size();
+    if (len == 0 || start[0] != u'#') {
+        return {};
+    }
+
+    android::Res_value value = {};
+    bool error = false;
+    if (len == 4) {
+        value.dataType = android::Res_value::TYPE_INT_COLOR_RGB4;
+        value.data = 0xff000000u;
+        value.data |= parseHex(start[1], &error) << 20;
+        value.data |= parseHex(start[1], &error) << 16;
+        value.data |= parseHex(start[2], &error) << 12;
+        value.data |= parseHex(start[2], &error) << 8;
+        value.data |= parseHex(start[3], &error) << 4;
+        value.data |= parseHex(start[3], &error);
+    } else if (len == 5) {
+        value.dataType = android::Res_value::TYPE_INT_COLOR_ARGB4;
+        value.data |= parseHex(start[1], &error) << 28;
+        value.data |= parseHex(start[1], &error) << 24;
+        value.data |= parseHex(start[2], &error) << 20;
+        value.data |= parseHex(start[2], &error) << 16;
+        value.data |= parseHex(start[3], &error) << 12;
+        value.data |= parseHex(start[3], &error) << 8;
+        value.data |= parseHex(start[4], &error) << 4;
+        value.data |= parseHex(start[4], &error);
+    } else if (len == 7) {
+        value.dataType = android::Res_value::TYPE_INT_COLOR_RGB8;
+        value.data = 0xff000000u;
+        value.data |= parseHex(start[1], &error) << 20;
+        value.data |= parseHex(start[2], &error) << 16;
+        value.data |= parseHex(start[3], &error) << 12;
+        value.data |= parseHex(start[4], &error) << 8;
+        value.data |= parseHex(start[5], &error) << 4;
+        value.data |= parseHex(start[6], &error);
+    } else if (len == 9) {
+        value.dataType = android::Res_value::TYPE_INT_COLOR_ARGB8;
+        value.data |= parseHex(start[1], &error) << 28;
+        value.data |= parseHex(start[2], &error) << 24;
+        value.data |= parseHex(start[3], &error) << 20;
+        value.data |= parseHex(start[4], &error) << 16;
+        value.data |= parseHex(start[5], &error) << 12;
+        value.data |= parseHex(start[6], &error) << 8;
+        value.data |= parseHex(start[7], &error) << 4;
+        value.data |= parseHex(start[8], &error);
+    } else {
+        return {};
+    }
+    return error ? std::unique_ptr<BinaryPrimitive>() : util::make_unique<BinaryPrimitive>(value);
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseBool(const StringPiece16& str) {
+    StringPiece16 trimmedStr(util::trimWhitespace(str));
+    uint32_t data = 0;
+    if (trimmedStr == u"true" || trimmedStr == u"TRUE") {
+        data = 1;
+    } else if (trimmedStr != u"false" && trimmedStr != u"FALSE") {
+        return {};
+    }
+    android::Res_value value = {};
+    value.dataType = android::Res_value::TYPE_INT_BOOLEAN;
+    value.data = data;
+    return util::make_unique<BinaryPrimitive>(value);
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseInt(const StringPiece16& str) {
+    android::Res_value value;
+    if (!android::ResTable::stringToInt(str.data(), str.size(), &value)) {
+        return {};
+    }
+    return util::make_unique<BinaryPrimitive>(value);
+}
+
+std::unique_ptr<BinaryPrimitive> ResourceParser::tryParseFloat(const StringPiece16& str) {
+    android::Res_value value;
+    if (!android::ResTable::stringToFloat(str.data(), str.size(), &value)) {
+        return {};
+    }
+    return util::make_unique<BinaryPrimitive>(value);
+}
+
+uint32_t ResourceParser::androidTypeToAttributeTypeMask(uint16_t type) {
+    switch (type) {
+        case android::Res_value::TYPE_NULL:
+        case android::Res_value::TYPE_REFERENCE:
+        case android::Res_value::TYPE_ATTRIBUTE:
+        case android::Res_value::TYPE_DYNAMIC_REFERENCE:
+            return android::ResTable_map::TYPE_REFERENCE;
+
+        case android::Res_value::TYPE_STRING:
+            return android::ResTable_map::TYPE_STRING;
+
+        case android::Res_value::TYPE_FLOAT:
+            return android::ResTable_map::TYPE_FLOAT;
+
+        case android::Res_value::TYPE_DIMENSION:
+            return android::ResTable_map::TYPE_DIMENSION;
+
+        case android::Res_value::TYPE_FRACTION:
+            return android::ResTable_map::TYPE_FRACTION;
+
+        case android::Res_value::TYPE_INT_DEC:
+        case android::Res_value::TYPE_INT_HEX:
+            return android::ResTable_map::TYPE_INTEGER |
+                    android::ResTable_map::TYPE_ENUM |
+                    android::ResTable_map::TYPE_FLAGS;
+
+        case android::Res_value::TYPE_INT_BOOLEAN:
+            return android::ResTable_map::TYPE_BOOLEAN;
+
+        case android::Res_value::TYPE_INT_COLOR_ARGB8:
+        case android::Res_value::TYPE_INT_COLOR_RGB8:
+        case android::Res_value::TYPE_INT_COLOR_ARGB4:
+        case android::Res_value::TYPE_INT_COLOR_RGB4:
+            return android::ResTable_map::TYPE_COLOR;
+
+        default:
+            return 0;
+    };
+}
+
+std::unique_ptr<Item> ResourceParser::parseItemForAttribute(
+        const StringPiece16& value, uint32_t typeMask, const StringPiece16& defaultPackage,
+        std::function<void(const ResourceName&)> onCreateReference) {
+    std::unique_ptr<BinaryPrimitive> nullOrEmpty = tryParseNullOrEmpty(value);
+    if (nullOrEmpty) {
+        return std::move(nullOrEmpty);
+    }
+
+    bool create = false;
+    std::unique_ptr<Reference> reference = tryParseReference(value, defaultPackage, &create);
+    if (reference) {
+        if (create && onCreateReference) {
+            onCreateReference(reference->name);
+        }
+        return std::move(reference);
+    }
+
+    if (typeMask & android::ResTable_map::TYPE_COLOR) {
+        // Try parsing this as a color.
+        std::unique_ptr<BinaryPrimitive> color = tryParseColor(value);
+        if (color) {
+            return std::move(color);
+        }
+    }
+
+    if (typeMask & android::ResTable_map::TYPE_BOOLEAN) {
+        // Try parsing this as a boolean.
+        std::unique_ptr<BinaryPrimitive> boolean = tryParseBool(value);
+        if (boolean) {
+            return std::move(boolean);
+        }
+    }
+
+    if (typeMask & android::ResTable_map::TYPE_INTEGER) {
+        // Try parsing this as an integer.
+        std::unique_ptr<BinaryPrimitive> integer = tryParseInt(value);
+        if (integer) {
+            return std::move(integer);
+        }
+    }
+
+    const uint32_t floatMask = android::ResTable_map::TYPE_FLOAT |
+            android::ResTable_map::TYPE_DIMENSION |
+            android::ResTable_map::TYPE_FRACTION;
+    if (typeMask & floatMask) {
+        // Try parsing this as a float.
+        std::unique_ptr<BinaryPrimitive> floatingPoint = tryParseFloat(value);
+        if (floatingPoint) {
+            if (typeMask & androidTypeToAttributeTypeMask(floatingPoint->value.dataType)) {
+                return std::move(floatingPoint);
+            }
+        }
+    }
+    return {};
+}
+
+/**
+ * We successively try to parse the string as a resource type that the Attribute
+ * allows.
+ */
+std::unique_ptr<Item> ResourceParser::parseItemForAttribute(
+        const StringPiece16& str, const Attribute& attr, const StringPiece16& defaultPackage,
+        std::function<void(const ResourceName&)> onCreateReference) {
+    const uint32_t typeMask = attr.typeMask;
+    std::unique_ptr<Item> value = parseItemForAttribute(str, typeMask, defaultPackage,
+                                                        onCreateReference);
+    if (value) {
+        return value;
+    }
+
+    if (typeMask & android::ResTable_map::TYPE_ENUM) {
+        // Try parsing this as an enum.
+        std::unique_ptr<BinaryPrimitive> enumValue = tryParseEnumSymbol(attr, str);
+        if (enumValue) {
+            return std::move(enumValue);
+        }
+    }
+
+    if (typeMask & android::ResTable_map::TYPE_FLAGS) {
+        // Try parsing this as a flag.
+        std::unique_ptr<BinaryPrimitive> flagValue = tryParseFlagSymbol(attr, str);
+        if (flagValue) {
+            return std::move(flagValue);
+        }
+    }
+    return {};
+}
+
+ResourceParser::ResourceParser(const std::shared_ptr<ResourceTable>& table, const Source& source,
+                               const ConfigDescription& config,
+                               const std::shared_ptr<XmlPullParser>& parser) :
+        mTable(table), mSource(source), mConfig(config), mLogger(source),
+        mParser(std::make_shared<XliffXmlPullParser>(parser)) {
+}
+
+/**
+ * Build a string from XML that converts nested elements into Span objects.
+ */
+bool ResourceParser::flattenXmlSubtree(XmlPullParser* parser, std::u16string* outRawString,
+                                       StyleString* outStyleString) {
+    std::vector<Span> spanStack;
+
+    outRawString->clear();
+    outStyleString->spans.clear();
+    util::StringBuilder builder;
+    size_t depth = 1;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        const XmlPullParser::Event event = parser->getEvent();
+        if (event == XmlPullParser::Event::kEndElement) {
+            depth--;
+            if (depth == 0) {
+                break;
+            }
+
+            spanStack.back().lastChar = builder.str().size();
+            outStyleString->spans.push_back(spanStack.back());
+            spanStack.pop_back();
+
+        } else if (event == XmlPullParser::Event::kText) {
+            // TODO(adamlesinski): Verify format strings.
+            outRawString->append(parser->getText());
+            builder.append(parser->getText());
+
+        } else if (event == XmlPullParser::Event::kStartElement) {
+            if (parser->getElementNamespace().size() > 0) {
+                mLogger.warn(parser->getLineNumber())
+                        << "skipping element '"
+                        << parser->getElementName()
+                        << "' with unknown namespace '"
+                        << parser->getElementNamespace()
+                        << "'."
+                        << std::endl;
+                XmlPullParser::skipCurrentElement(parser);
+                continue;
+            }
+            depth++;
+
+            // Build a span object out of the nested element.
+            std::u16string spanName = parser->getElementName();
+            const auto endAttrIter = parser->endAttributes();
+            for (auto attrIter = parser->beginAttributes(); attrIter != endAttrIter; ++attrIter) {
+                spanName += u";";
+                spanName += attrIter->name;
+                spanName += u"=";
+                spanName += attrIter->value;
+            }
+
+            if (builder.str().size() > std::numeric_limits<uint32_t>::max()) {
+                mLogger.error(parser->getLineNumber())
+                        << "style string '"
+                        << builder.str()
+                        << "' is too long."
+                        << std::endl;
+                return false;
+            }
+            spanStack.push_back(Span{ spanName, static_cast<uint32_t>(builder.str().size()) });
+
+        } else if (event == XmlPullParser::Event::kComment) {
+            // Skip
+        } else {
+            mLogger.warn(parser->getLineNumber())
+                    << "unknown event "
+                    << event
+                    << "."
+                    << std::endl;
+        }
+    }
+    assert(spanStack.empty() && "spans haven't been fully processed");
+
+    outStyleString->str = builder.str();
+    return true;
+}
+
+bool ResourceParser::parse() {
+    while (XmlPullParser::isGoodEvent(mParser->next())) {
+        if (mParser->getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser parser(mParser.get());
+        if (!parser.getElementNamespace().empty() ||
+                parser.getElementName() != u"resources") {
+            mLogger.error(parser.getLineNumber())
+                    << "root element must be <resources> in the global namespace."
+                    << std::endl;
+            return false;
+        }
+
+        if (!parseResources(&parser)) {
+            return false;
+        }
+    }
+
+    if (mParser->getEvent() == XmlPullParser::Event::kBadDocument) {
+        mLogger.error(mParser->getLineNumber())
+                << mParser->getLastError()
+                << std::endl;
+        return false;
+    }
+    return true;
+}
+
+bool ResourceParser::parseResources(XmlPullParser* parser) {
+    bool success = true;
+
+    std::u16string comment;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        const XmlPullParser::Event event = parser->getEvent();
+        if (event == XmlPullParser::Event::kComment) {
+            comment = parser->getComment();
+            continue;
+        }
+
+        if (event == XmlPullParser::Event::kText) {
+            if (!util::trimWhitespace(parser->getText()).empty()) {
+                comment = u"";
+            }
+            continue;
+        }
+
+        if (event != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser childParser(parser);
+
+        if (!childParser.getElementNamespace().empty()) {
+            // Skip unknown namespace.
+            continue;
+        }
+
+        StringPiece16 name = childParser.getElementName();
+        if (name == u"skip" || name == u"eat-comment") {
+            continue;
+        }
+
+        if (name == u"private-symbols") {
+            // Handle differently.
+            mLogger.note(childParser.getLineNumber())
+                    << "got a <private-symbols> tag."
+                    << std::endl;
+            continue;
+        }
+
+        const auto endAttrIter = childParser.endAttributes();
+        auto attrIter = childParser.findAttribute(u"", u"name");
+        if (attrIter == endAttrIter || attrIter->value.empty()) {
+            mLogger.error(childParser.getLineNumber())
+                    << "<" << name << "> tag must have a 'name' attribute."
+                    << std::endl;
+            success = false;
+            continue;
+        }
+
+        // Copy because our iterator will go out of scope when
+        // we parse more XML.
+        std::u16string attributeName = attrIter->value;
+
+        if (name == u"item") {
+            // Items simply have their type encoded in the type attribute.
+            auto typeIter = childParser.findAttribute(u"", u"type");
+            if (typeIter == endAttrIter || typeIter->value.empty()) {
+                mLogger.error(childParser.getLineNumber())
+                        << "<item> must have a 'type' attribute."
+                        << std::endl;
+                success = false;
+                continue;
+            }
+            name = typeIter->value;
+        }
+
+        if (name == u"id") {
+            success &= mTable->addResource(ResourceNameRef{ {}, ResourceType::kId, attributeName },
+                                           {}, mSource.line(childParser.getLineNumber()),
+                                           util::make_unique<Id>());
+        } else if (name == u"string") {
+            success &= parseString(&childParser,
+                                   ResourceNameRef{ {}, ResourceType::kString, attributeName });
+        } else if (name == u"color") {
+            success &= parseColor(&childParser,
+                                  ResourceNameRef{ {}, ResourceType::kColor, attributeName });
+        } else if (name == u"drawable") {
+            success &= parseColor(&childParser,
+                                  ResourceNameRef{ {}, ResourceType::kDrawable, attributeName });
+        } else if (name == u"bool") {
+            success &= parsePrimitive(&childParser,
+                                      ResourceNameRef{ {}, ResourceType::kBool, attributeName });
+        } else if (name == u"integer") {
+            success &= parsePrimitive(
+                    &childParser,
+                    ResourceNameRef{ {}, ResourceType::kInteger, attributeName });
+        } else if (name == u"dimen") {
+            success &= parsePrimitive(&childParser,
+                                      ResourceNameRef{ {}, ResourceType::kDimen, attributeName });
+        } else if (name == u"fraction") {
+//          success &= parsePrimitive(
+//                  &childParser,
+//                  ResourceNameRef{ {}, ResourceType::kFraction, attributeName });
+        } else if (name == u"style") {
+            success &= parseStyle(&childParser,
+                                  ResourceNameRef{ {}, ResourceType::kStyle, attributeName });
+        } else if (name == u"plurals") {
+            success &= parsePlural(&childParser,
+                                   ResourceNameRef{ {}, ResourceType::kPlurals, attributeName });
+        } else if (name == u"array") {
+            success &= parseArray(&childParser,
+                                  ResourceNameRef{ {}, ResourceType::kArray, attributeName },
+                                  android::ResTable_map::TYPE_ANY);
+        } else if (name == u"string-array") {
+            success &= parseArray(&childParser,
+                                  ResourceNameRef{ {}, ResourceType::kArray, attributeName },
+                                  android::ResTable_map::TYPE_STRING);
+        } else if (name == u"integer-array") {
+            success &= parseArray(&childParser,
+                                  ResourceNameRef{ {}, ResourceType::kArray, attributeName },
+                                  android::ResTable_map::TYPE_INTEGER);
+        } else if (name == u"public") {
+            success &= parsePublic(&childParser, attributeName);
+        } else if (name == u"declare-styleable") {
+            success &= parseDeclareStyleable(
+                    &childParser,
+                    ResourceNameRef{ {}, ResourceType::kStyleable, attributeName });
+        } else if (name == u"attr") {
+            success &= parseAttr(&childParser,
+                                 ResourceNameRef{ {}, ResourceType::kAttr, attributeName });
+        } else if (name == u"bag") {
+        } else if (name == u"public-padding") {
+        } else if (name == u"java-symbol") {
+        } else if (name == u"add-resource") {
+       }
+    }
+
+    if (parser->getEvent() == XmlPullParser::Event::kBadDocument) {
+        mLogger.error(parser->getLineNumber())
+                << parser->getLastError()
+                << std::endl;
+        return false;
+    }
+    return success;
+}
+
+
+
+enum {
+    kAllowRawString = true,
+    kNoRawString = false
+};
+
+/**
+ * Reads the entire XML subtree and attempts to parse it as some Item,
+ * with typeMask denoting which items it can be. If allowRawValue is
+ * true, a RawString is returned if the XML couldn't be parsed as
+ * an Item. If allowRawValue is false, nullptr is returned in this
+ * case.
+ */
+std::unique_ptr<Item> ResourceParser::parseXml(XmlPullParser* parser, uint32_t typeMask,
+                                               bool allowRawValue) {
+    const size_t beginXmlLine = parser->getLineNumber();
+
+    std::u16string rawValue;
+    StyleString styleString;
+    if (!flattenXmlSubtree(parser, &rawValue, &styleString)) {
+        return {};
+    }
+
+    StringPool& pool = mTable->getValueStringPool();
+
+    if (!styleString.spans.empty()) {
+        // This can only be a StyledString.
+        return util::make_unique<StyledString>(
+                pool.makeRef(styleString, StringPool::Context{ 1, mConfig }));
+    }
+
+    auto onCreateReference = [&](const ResourceName& name) {
+        mTable->addResource(name, {}, mSource.line(beginXmlLine), util::make_unique<Id>());
+    };
+
+    // Process the raw value.
+    std::unique_ptr<Item> processedItem = parseItemForAttribute(rawValue, typeMask,
+                                                                mTable->getPackage(),
+                                                                onCreateReference);
+    if (processedItem) {
+        return processedItem;
+    }
+
+    // Try making a regular string.
+    if (typeMask & android::ResTable_map::TYPE_STRING) {
+        // Use the trimmed, escaped string.
+        return util::make_unique<String>(
+                pool.makeRef(styleString.str, StringPool::Context{ 1, mConfig }));
+    }
+
+    // We can't parse this so return a RawString if we are allowed.
+    if (allowRawValue) {
+        return util::make_unique<RawString>(
+                pool.makeRef(rawValue, StringPool::Context{ 1, mConfig }));
+    }
+    return {};
+}
+
+bool ResourceParser::parseString(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+
+    // Mark the string as untranslateable if needed.
+    const auto endAttrIter = parser->endAttributes();
+    auto attrIter = parser->findAttribute(u"", u"untranslateable");
+    // bool untranslateable = attrIter != endAttrIter;
+    // TODO(adamlesinski): Do something with this (mark the string).
+
+    // Deal with the product.
+    attrIter = parser->findAttribute(u"", u"product");
+    if (attrIter != endAttrIter) {
+        if (attrIter->value != u"default" && attrIter->value != u"phone") {
+            // TODO(adamlesinski): Match products.
+            return true;
+        }
+    }
+
+    std::unique_ptr<Item> processedItem = parseXml(parser, android::ResTable_map::TYPE_STRING,
+                                                   kNoRawString);
+    if (!processedItem) {
+        mLogger.error(source.line)
+                << "not a valid string."
+                << std::endl;
+        return false;
+    }
+
+    return mTable->addResource(resourceName, mConfig, source, std::move(processedItem));
+}
+
+bool ResourceParser::parseColor(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+
+    std::unique_ptr<Item> item = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString);
+    if (!item) {
+        mLogger.error(source.line) << "invalid color." << std::endl;
+        return false;
+    }
+    return mTable->addResource(resourceName, mConfig, source, std::move(item));
+}
+
+bool ResourceParser::parsePrimitive(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+
+    uint32_t typeMask = 0;
+    switch (resourceName.type) {
+        case ResourceType::kInteger:
+            typeMask |= android::ResTable_map::TYPE_INTEGER;
+            break;
+
+        case ResourceType::kDimen:
+            typeMask |= android::ResTable_map::TYPE_DIMENSION
+                     | android::ResTable_map::TYPE_FLOAT
+                     | android::ResTable_map::TYPE_FRACTION;
+            break;
+
+        case ResourceType::kBool:
+            typeMask |= android::ResTable_map::TYPE_BOOLEAN;
+            break;
+
+        default:
+            assert(false);
+            break;
+    }
+
+    std::unique_ptr<Item> item = parseXml(parser, typeMask, kNoRawString);
+    if (!item) {
+        mLogger.error(source.line)
+                << "invalid "
+                << resourceName.type
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    return mTable->addResource(resourceName, mConfig, source, std::move(item));
+}
+
+bool ResourceParser::parsePublic(XmlPullParser* parser, const StringPiece16& name) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+
+    const auto endAttrIter = parser->endAttributes();
+    const auto typeAttrIter = parser->findAttribute(u"", u"type");
+    if (typeAttrIter == endAttrIter || typeAttrIter->value.empty()) {
+        mLogger.error(source.line)
+                << "<public> must have a 'type' attribute."
+                << std::endl;
+        return false;
+    }
+
+    const ResourceType* parsedType = parseResourceType(typeAttrIter->value);
+    if (!parsedType) {
+        mLogger.error(source.line)
+                << "invalid resource type '"
+                << typeAttrIter->value
+                << "' in <public>."
+                << std::endl;
+        return false;
+    }
+
+    ResourceNameRef resourceName { {}, *parsedType, name };
+    ResourceId resourceId;
+
+    const auto idAttrIter = parser->findAttribute(u"", u"id");
+    if (idAttrIter != endAttrIter && !idAttrIter->value.empty()) {
+        android::Res_value val;
+        bool result = android::ResTable::stringToInt(idAttrIter->value.data(),
+                                                     idAttrIter->value.size(), &val);
+        resourceId.id = val.data;
+        if (!result || !resourceId.isValid()) {
+            mLogger.error(source.line)
+                    << "invalid resource ID '"
+                    << idAttrIter->value
+                    << "' in <public>."
+                    << std::endl;
+            return false;
+        }
+    }
+
+    if (*parsedType == ResourceType::kId) {
+        // An ID marked as public is also the definition of an ID.
+        mTable->addResource(resourceName, {}, source, util::make_unique<Id>());
+    }
+
+    return mTable->markPublic(resourceName, resourceId, source);
+}
+
+static uint32_t parseFormatType(const StringPiece16& piece) {
+    if (piece == u"reference")      return android::ResTable_map::TYPE_REFERENCE;
+    else if (piece == u"string")    return android::ResTable_map::TYPE_STRING;
+    else if (piece == u"integer")   return android::ResTable_map::TYPE_INTEGER;
+    else if (piece == u"boolean")   return android::ResTable_map::TYPE_BOOLEAN;
+    else if (piece == u"color")     return android::ResTable_map::TYPE_COLOR;
+    else if (piece == u"float")     return android::ResTable_map::TYPE_FLOAT;
+    else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION;
+    else if (piece == u"fraction")  return android::ResTable_map::TYPE_FRACTION;
+    else if (piece == u"enum")      return android::ResTable_map::TYPE_ENUM;
+    else if (piece == u"flags")     return android::ResTable_map::TYPE_FLAGS;
+    return 0;
+}
+
+static uint32_t parseFormatAttribute(const StringPiece16& str) {
+    uint32_t mask = 0;
+    for (StringPiece16 part : util::tokenize(str, u'|')) {
+        StringPiece16 trimmedPart = util::trimWhitespace(part);
+        uint32_t type = parseFormatType(trimmedPart);
+        if (type == 0) {
+            return 0;
+        }
+        mask |= type;
+    }
+    return mask;
+}
+
+bool ResourceParser::parseAttr(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+    std::unique_ptr<Attribute> attr = parseAttrImpl(parser, resourceName, false);
+    if (!attr) {
+        return false;
+    }
+    return mTable->addResource(resourceName, mConfig, source, std::move(attr));
+}
+
+std::unique_ptr<Attribute> ResourceParser::parseAttrImpl(XmlPullParser* parser,
+                                                         const ResourceNameRef& resourceName,
+                                                         bool weak) {
+    uint32_t typeMask = 0;
+
+    const auto endAttrIter = parser->endAttributes();
+    const auto formatAttrIter = parser->findAttribute(u"", u"format");
+    if (formatAttrIter != endAttrIter) {
+        typeMask = parseFormatAttribute(formatAttrIter->value);
+        if (typeMask == 0) {
+            mLogger.error(parser->getLineNumber())
+                    << "invalid attribute format '"
+                    << formatAttrIter->value
+                    << "'."
+                    << std::endl;
+            return {};
+        }
+    }
+
+    std::vector<Attribute::Symbol> items;
+
+    bool error = false;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser childParser(parser);
+
+        const std::u16string& name = childParser.getElementName();
+        if (!childParser.getElementNamespace().empty()
+                || (name != u"flag" && name != u"enum")) {
+            mLogger.error(childParser.getLineNumber())
+                    << "unexpected tag <"
+                    << name
+                    << "> in <attr>."
+                    << std::endl;
+            error = true;
+            continue;
+        }
+
+        if (name == u"enum") {
+            if (typeMask & android::ResTable_map::TYPE_FLAGS) {
+                mLogger.error(childParser.getLineNumber())
+                        << "can not define an <enum>; already defined a <flag>."
+                        << std::endl;
+                error = true;
+                continue;
+            }
+            typeMask |= android::ResTable_map::TYPE_ENUM;
+        } else if (name == u"flag") {
+            if (typeMask & android::ResTable_map::TYPE_ENUM) {
+                mLogger.error(childParser.getLineNumber())
+                        << "can not define a <flag>; already defined an <enum>."
+                        << std::endl;
+                error = true;
+                continue;
+            }
+            typeMask |= android::ResTable_map::TYPE_FLAGS;
+        }
+
+        Attribute::Symbol item;
+        if (parseEnumOrFlagItem(&childParser, name, &item)) {
+            if (!mTable->addResource(item.symbol.name, mConfig,
+                                     mSource.line(childParser.getLineNumber()),
+                                     util::make_unique<Id>())) {
+                error = true;
+            } else {
+                items.push_back(std::move(item));
+            }
+        } else {
+            error = true;
+        }
+    }
+
+    if (error) {
+        return {};
+    }
+
+    std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak);
+    attr->symbols.swap(items);
+    attr->typeMask = typeMask ? typeMask : uint32_t(android::ResTable_map::TYPE_ANY);
+    return attr;
+}
+
+bool ResourceParser::parseEnumOrFlagItem(XmlPullParser* parser, const StringPiece16& tag,
+                                         Attribute::Symbol* outSymbol) {
+    const auto attrIterEnd = parser->endAttributes();
+    const auto nameAttrIter = parser->findAttribute(u"", u"name");
+    if (nameAttrIter == attrIterEnd || nameAttrIter->value.empty()) {
+        mLogger.error(parser->getLineNumber())
+                << "no attribute 'name' found for tag <" << tag << ">."
+                << std::endl;
+        return false;
+    }
+
+    const auto valueAttrIter = parser->findAttribute(u"", u"value");
+    if (valueAttrIter == attrIterEnd || valueAttrIter->value.empty()) {
+        mLogger.error(parser->getLineNumber())
+                << "no attribute 'value' found for tag <" << tag << ">."
+                << std::endl;
+        return false;
+    }
+
+    android::Res_value val;
+    if (!android::ResTable::stringToInt(valueAttrIter->value.data(),
+                                        valueAttrIter->value.size(), &val)) {
+        mLogger.error(parser->getLineNumber())
+                << "invalid value '"
+                << valueAttrIter->value
+                << "' for <" << tag << ">; must be an integer."
+                << std::endl;
+        return false;
+    }
+
+    outSymbol->symbol.name = ResourceName {
+            mTable->getPackage(), ResourceType::kId, nameAttrIter->value };
+    outSymbol->value = val.data;
+    return true;
+}
+
+static bool parseXmlAttributeName(StringPiece16 str, ResourceNameRef* outRef) {
+    str = util::trimWhitespace(str);
+    const char16_t* const start = str.data();
+    const char16_t* const end = start + str.size();
+    const char16_t* p = start;
+
+    StringPiece16 package;
+    StringPiece16 name;
+    while (p != end) {
+        if (*p == u':') {
+            package = StringPiece16(start, p - start);
+            name = StringPiece16(p + 1, end - (p + 1));
+            break;
+        }
+        p++;
+    }
+
+    outRef->package = package;
+    outRef->type = ResourceType::kAttr;
+    if (name.size() == 0) {
+        outRef->entry = str;
+    } else {
+        outRef->entry = name;
+    }
+    return true;
+}
+
+bool ResourceParser::parseUntypedItem(XmlPullParser* parser, Style& style) {
+    const auto endAttrIter = parser->endAttributes();
+    const auto nameAttrIter = parser->findAttribute(u"", u"name");
+    if (nameAttrIter == endAttrIter || nameAttrIter->value.empty()) {
+        mLogger.error(parser->getLineNumber())
+                << "<item> must have a 'name' attribute."
+                << std::endl;
+        return false;
+    }
+
+    ResourceNameRef keyRef;
+    if (!parseXmlAttributeName(nameAttrIter->value, &keyRef)) {
+        mLogger.error(parser->getLineNumber())
+                << "invalid attribute name '"
+                << nameAttrIter->value
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    if (keyRef.package.empty()) {
+        keyRef.package = mTable->getPackage();
+    }
+
+    // Create a copy instead of a reference because we
+    // are about to invalidate keyRef when advancing the parser.
+    ResourceName key = keyRef.toResourceName();
+
+    std::unique_ptr<Item> value = parseXml(parser, 0, kAllowRawString);
+    if (!value) {
+        return false;
+    }
+
+    style.entries.push_back(Style::Entry{ Reference(key), std::move(value) });
+    return true;
+}
+
+bool ResourceParser::parseStyle(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+    std::unique_ptr<Style> style = util::make_unique<Style>();
+
+    const auto endAttrIter = parser->endAttributes();
+    const auto parentAttrIter = parser->findAttribute(u"", u"parent");
+    if (parentAttrIter != endAttrIter) {
+        ResourceNameRef ref;
+        bool create = false;
+        bool privateRef = false;
+        if (tryParseReference(parentAttrIter->value, &ref, &create, &privateRef)) {
+            if (create) {
+                mLogger.error(source.line)
+                        << "parent of style can not be an ID."
+                        << std::endl;
+                return false;
+            }
+            style->parent.name = ref.toResourceName();
+            style->parent.privateReference = privateRef;
+        } else if (tryParseAttributeReference(parentAttrIter->value, &ref)) {
+            style->parent.name = ref.toResourceName();
+        } else {
+            // TODO(adamlesinski): Try parsing without the '@' or '?'.
+            // Also, make sure to check the entry name for weird symbols.
+            style->parent.name = ResourceName {
+                {}, ResourceType::kStyle, parentAttrIter->value
+            };
+        }
+
+        if (style->parent.name.package.empty()) {
+            style->parent.name.package = mTable->getPackage();
+        }
+    }
+
+    bool success = true;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser childParser(parser);
+        const std::u16string& name = childParser.getElementName();
+        if (name == u"item") {
+            success &= parseUntypedItem(&childParser, *style);
+        } else {
+            mLogger.error(childParser.getLineNumber())
+                    << "unexpected tag <"
+                    << name
+                    << "> in <style> resource."
+                    << std::endl;
+            success = false;
+        }
+    }
+
+    if (!success) {
+        return false;
+    }
+
+    return mTable->addResource(resourceName, mConfig, source, std::move(style));
+}
+
+bool ResourceParser::parseArray(XmlPullParser* parser, const ResourceNameRef& resourceName,
+                                uint32_t typeMask) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+    std::unique_ptr<Array> array = util::make_unique<Array>();
+
+    bool error = false;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser childParser(parser);
+
+        if (childParser.getElementName() != u"item") {
+            mLogger.error(childParser.getLineNumber())
+                    << "unexpected tag <"
+                    << childParser.getElementName()
+                    << "> in <array> resource."
+                    << std::endl;
+            error = true;
+            continue;
+        }
+
+        std::unique_ptr<Item> item = parseXml(&childParser, typeMask, kNoRawString);
+        if (!item) {
+            error = true;
+            continue;
+        }
+        array->items.emplace_back(std::move(item));
+    }
+
+    if (error) {
+        return false;
+    }
+
+    return mTable->addResource(resourceName, mConfig, source, std::move(array));
+}
+
+bool ResourceParser::parsePlural(XmlPullParser* parser, const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+    std::unique_ptr<Plural> plural = util::make_unique<Plural>();
+
+    bool success = true;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser childParser(parser);
+
+        if (!childParser.getElementNamespace().empty() ||
+                childParser.getElementName() != u"item") {
+            success = false;
+            continue;
+        }
+
+        const auto endAttrIter = childParser.endAttributes();
+        auto attrIter = childParser.findAttribute(u"", u"quantity");
+        if (attrIter == endAttrIter || attrIter->value.empty()) {
+            mLogger.error(childParser.getLineNumber())
+                    << "<item> in <plurals> requires attribute 'quantity'."
+                    << std::endl;
+            success = false;
+            continue;
+        }
+
+        StringPiece16 trimmedQuantity = util::trimWhitespace(attrIter->value);
+        size_t index = 0;
+        if (trimmedQuantity == u"zero") {
+            index = Plural::Zero;
+        } else if (trimmedQuantity == u"one") {
+            index = Plural::One;
+        } else if (trimmedQuantity == u"two") {
+            index = Plural::Two;
+        } else if (trimmedQuantity == u"few") {
+            index = Plural::Few;
+        } else if (trimmedQuantity == u"many") {
+            index = Plural::Many;
+        } else if (trimmedQuantity == u"other") {
+            index = Plural::Other;
+        } else {
+            mLogger.error(childParser.getLineNumber())
+                    << "<item> in <plural> has invalid value '"
+                    << trimmedQuantity
+                    << "' for attribute 'quantity'."
+                    << std::endl;
+            success = false;
+            continue;
+        }
+
+        if (plural->values[index]) {
+            mLogger.error(childParser.getLineNumber())
+                    << "duplicate quantity '"
+                    << trimmedQuantity
+                    << "'."
+                    << std::endl;
+            success = false;
+            continue;
+        }
+
+        if (!(plural->values[index] = parseXml(&childParser, android::ResTable_map::TYPE_STRING,
+                                               kNoRawString))) {
+            success = false;
+        }
+    }
+
+    if (!success) {
+        return false;
+    }
+
+    return mTable->addResource(resourceName, mConfig, source, std::move(plural));
+}
+
+bool ResourceParser::parseDeclareStyleable(XmlPullParser* parser,
+                                           const ResourceNameRef& resourceName) {
+    const SourceLine source = mSource.line(parser->getLineNumber());
+    std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>();
+
+    bool success = true;
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        if (parser->getEvent() != XmlPullParser::Event::kStartElement) {
+            continue;
+        }
+
+        ScopedXmlPullParser childParser(parser);
+
+        const std::u16string& elementName = childParser.getElementName();
+        if (elementName == u"attr") {
+            const auto endAttrIter = childParser.endAttributes();
+            auto attrIter = childParser.findAttribute(u"", u"name");
+            if (attrIter == endAttrIter || attrIter->value.empty()) {
+                mLogger.error(childParser.getLineNumber())
+                        << "<attr> tag must have a 'name' attribute."
+                        << std::endl;
+                success = false;
+                continue;
+            }
+
+            // Copy because our iterator will be invalidated.
+            std::u16string attrName = attrIter->value;
+
+            ResourceNameRef attrResourceName = {
+                    mTable->getPackage(),
+                    ResourceType::kAttr,
+                    attrName
+            };
+
+            std::unique_ptr<Attribute> attr = parseAttrImpl(&childParser, attrResourceName, true);
+            if (!attr) {
+                success = false;
+                continue;
+            }
+
+            styleable->entries.emplace_back(attrResourceName);
+
+            success &= mTable->addResource(attrResourceName, mConfig,
+                                           mSource.line(childParser.getLineNumber()),
+                                           std::move(attr));
+
+        } else if (elementName != u"eat-comment" && elementName != u"skip") {
+            mLogger.error(childParser.getLineNumber())
+                    << "<"
+                    << elementName
+                    << "> is not allowed inside <declare-styleable>."
+                    << std::endl;
+            success = false;
+        }
+    }
+
+    if (!success) {
+        return false;
+    }
+
+    return mTable->addResource(resourceName, mConfig, source, std::move(styleable));
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
new file mode 100644
index 0000000..96bba4f
--- /dev/null
+++ b/tools/aapt2/ResourceParser.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RESOURCE_PARSER_H
+#define AAPT_RESOURCE_PARSER_H
+
+#include "ConfigDescription.h"
+#include "Logger.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "StringPiece.h"
+#include "StringPool.h"
+#include "XmlPullParser.h"
+
+#include <istream>
+#include <memory>
+
+namespace aapt {
+
+/*
+ * Parses an XML file for resources and adds them to a ResourceTable.
+ */
+class ResourceParser {
+public:
+    /*
+     * Extracts the package, type, and name from a string of the format:
+     *
+     *      [package:]type/name
+     *
+     * where the package can be empty. Validation must be performed on each
+     * individual extracted piece to verify that the pieces are valid.
+     */
+    static void extractResourceName(const StringPiece16& str, StringPiece16* outPackage,
+                                    StringPiece16* outType, StringPiece16* outEntry);
+
+    /*
+     * Returns true if the string was parsed as a reference (@[+][package:]type/name), with
+     * `outReference` set to the parsed reference.
+     *
+     * If '+' was present in the reference, `outCreate` is set to true.
+     * If '*' was present in the reference, `outPrivate` is set to true.
+     */
+    static bool tryParseReference(const StringPiece16& str, ResourceNameRef* outReference,
+                                  bool* outCreate, bool* outPrivate);
+
+    /*
+     * Returns true if the string was parsed as an attribute reference (?[package:]type/name),
+     * with `outReference` set to the parsed reference.
+     */
+    static bool tryParseAttributeReference(const StringPiece16& str,
+                                           ResourceNameRef* outReference);
+
+    /*
+     * Returns a Reference object if the string was parsed as a resource or attribute reference,
+     * ( @[+][package:]type/name | ?[package:]type/name )
+     * assigning defaultPackage if the package was not present in the string, and setting
+     * outCreate to true if the '+' was present in the string.
+     */
+    static std::unique_ptr<Reference> tryParseReference(const StringPiece16& str,
+                                                        const StringPiece16& defaultPackage,
+                                                        bool* outCreate);
+
+    /*
+     * Returns a BinaryPrimitve object representing @null or @empty if the string was parsed
+     * as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseNullOrEmpty(const StringPiece16& str);
+
+    /*
+     * Returns a BinaryPrimitve object representing a color if the string was parsed
+     * as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseColor(const StringPiece16& str);
+
+    /*
+     * Returns a BinaryPrimitve object representing a boolean if the string was parsed
+     * as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseBool(const StringPiece16& str);
+
+    /*
+     * Returns a BinaryPrimitve object representing an integer if the string was parsed
+     * as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseInt(const StringPiece16& str);
+
+    /*
+     * Returns a BinaryPrimitve object representing a floating point number
+     * (float, dimension, etc) if the string was parsed as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseFloat(const StringPiece16& str);
+
+    /*
+     * Returns a BinaryPrimitve object representing an enum symbol if the string was parsed
+     * as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseEnumSymbol(const Attribute& enumAttr,
+                                                               const StringPiece16& str);
+
+    /*
+     * Returns a BinaryPrimitve object representing a flag symbol if the string was parsed
+     * as one.
+     */
+    static std::unique_ptr<BinaryPrimitive> tryParseFlagSymbol(const Attribute& enumAttr,
+                                                               const StringPiece16& str);
+
+    /*
+     * Try to convert a string to an Item for the given attribute. The attribute will
+     * restrict what values the string can be converted to.
+     * The defaultPackage is used when the string is a reference with no defined package.
+     * The callback function onCreateReference is called when the parsed item is a
+     * reference to an ID that must be created (@+id/foo).
+     */
+    static std::unique_ptr<Item> parseItemForAttribute(
+            const StringPiece16& value, const Attribute& attr, const StringPiece16& defaultPackage,
+            std::function<void(const ResourceName&)> onCreateReference = {});
+
+    static std::unique_ptr<Item> parseItemForAttribute(
+            const StringPiece16& value, uint32_t typeMask, const StringPiece16& defaultPackage,
+            std::function<void(const ResourceName&)> onCreateReference = {});
+
+    static uint32_t androidTypeToAttributeTypeMask(uint16_t type);
+
+    ResourceParser(const std::shared_ptr<ResourceTable>& table, const Source& source,
+                   const ConfigDescription& config, const std::shared_ptr<XmlPullParser>& parser);
+
+    ResourceParser(const ResourceParser&) = delete; // No copy.
+
+    bool parse();
+
+private:
+    /*
+     * Parses the XML subtree as a StyleString (flattened XML representation for strings
+     * with formatting). If successful, `outStyleString`
+     * contains the escaped and whitespace trimmed text, while `outRawString`
+     * contains the unescaped text. Returns true on success.
+     */
+    bool flattenXmlSubtree(XmlPullParser* parser, std::u16string* outRawString,\
+                           StyleString* outStyleString);
+
+    /*
+     * Parses the XML subtree and converts it to an Item. The type of Item that can be
+     * parsed is denoted by the `typeMask`. If `allowRawValue` is true and the subtree
+     * can not be parsed as a regular Item, then a RawString is returned. Otherwise
+     * this returns nullptr.
+     */
+    std::unique_ptr<Item> parseXml(XmlPullParser* parser, uint32_t typeMask, bool allowRawValue);
+
+    bool parseResources(XmlPullParser* parser);
+    bool parseString(XmlPullParser* parser, const ResourceNameRef& resourceName);
+    bool parseColor(XmlPullParser* parser, const ResourceNameRef& resourceName);
+    bool parsePrimitive(XmlPullParser* parser, const ResourceNameRef& resourceName);
+    bool parsePublic(XmlPullParser* parser, const StringPiece16& name);
+    bool parseAttr(XmlPullParser* parser, const ResourceNameRef& resourceName);
+    std::unique_ptr<Attribute> parseAttrImpl(XmlPullParser* parser,
+                                             const ResourceNameRef& resourceName,
+                                             bool weak);
+    bool parseEnumOrFlagItem(XmlPullParser* parser, const StringPiece16& tag,
+                             Attribute::Symbol* outSymbol);
+    bool parseStyle(XmlPullParser* parser, const ResourceNameRef& resourceName);
+    bool parseUntypedItem(XmlPullParser* parser, Style& style);
+    bool parseDeclareStyleable(XmlPullParser* parser, const ResourceNameRef& resourceName);
+    bool parseArray(XmlPullParser* parser, const ResourceNameRef& resourceName, uint32_t typeMask);
+    bool parsePlural(XmlPullParser* parser, const ResourceNameRef& resourceName);
+
+    std::shared_ptr<ResourceTable> mTable;
+    Source mSource;
+    ConfigDescription mConfig;
+    SourceLogger mLogger;
+    std::shared_ptr<XmlPullParser> mParser;
+};
+
+} // namespace aapt
+
+#endif // AAPT_RESOURCE_PARSER_H
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
new file mode 100644
index 0000000..5afbaf4
--- /dev/null
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResourceParser.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "SourceXmlPullParser.h"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+
+TEST(ResourceParserReferenceTest, ParseReferenceWithNoPackage) {
+    ResourceNameRef expected = { {}, ResourceType::kColor, u"foo" };
+    ResourceNameRef actual;
+    bool create = false;
+    bool privateRef = false;
+    EXPECT_TRUE(ResourceParser::tryParseReference(u"@color/foo", &actual, &create, &privateRef));
+    EXPECT_EQ(expected, actual);
+    EXPECT_FALSE(create);
+    EXPECT_FALSE(privateRef);
+}
+
+TEST(ResourceParserReferenceTest, ParseReferenceWithPackage) {
+    ResourceNameRef expected = { u"android", ResourceType::kColor, u"foo" };
+    ResourceNameRef actual;
+    bool create = false;
+    bool privateRef = false;
+    EXPECT_TRUE(ResourceParser::tryParseReference(u"@android:color/foo", &actual, &create,
+                                                  &privateRef));
+    EXPECT_EQ(expected, actual);
+    EXPECT_FALSE(create);
+    EXPECT_FALSE(privateRef);
+}
+
+TEST(ResourceParserReferenceTest, ParseReferenceWithSurroundingWhitespace) {
+    ResourceNameRef expected = { u"android", ResourceType::kColor, u"foo" };
+    ResourceNameRef actual;
+    bool create = false;
+    bool privateRef = false;
+    EXPECT_TRUE(ResourceParser::tryParseReference(u"\t @android:color/foo\n \n\t", &actual,
+                                                  &create, &privateRef));
+    EXPECT_EQ(expected, actual);
+    EXPECT_FALSE(create);
+    EXPECT_FALSE(privateRef);
+}
+
+TEST(ResourceParserReferenceTest, ParseAutoCreateIdReference) {
+    ResourceNameRef expected = { u"android", ResourceType::kId, u"foo" };
+    ResourceNameRef actual;
+    bool create = false;
+    bool privateRef = false;
+    EXPECT_TRUE(ResourceParser::tryParseReference(u"@+android:id/foo", &actual, &create,
+                                                  &privateRef));
+    EXPECT_EQ(expected, actual);
+    EXPECT_TRUE(create);
+    EXPECT_FALSE(privateRef);
+}
+
+TEST(ResourceParserReferenceTest, ParsePrivateReference) {
+    ResourceNameRef expected = { u"android", ResourceType::kId, u"foo" };
+    ResourceNameRef actual;
+    bool create = false;
+    bool privateRef = false;
+    EXPECT_TRUE(ResourceParser::tryParseReference(u"@*android:id/foo", &actual, &create,
+                                                  &privateRef));
+    EXPECT_EQ(expected, actual);
+    EXPECT_FALSE(create);
+    EXPECT_TRUE(privateRef);
+}
+
+TEST(ResourceParserReferenceTest, FailToParseAutoCreateNonIdReference) {
+    bool create = false;
+    bool privateRef = false;
+    ResourceNameRef actual;
+    EXPECT_FALSE(ResourceParser::tryParseReference(u"@+android:color/foo", &actual, &create,
+                                                   &privateRef));
+}
+
+struct ResourceParserTest : public ::testing::Test {
+    virtual void SetUp() override {
+        mTable = std::make_shared<ResourceTable>();
+        mTable->setPackage(u"android");
+    }
+
+    ::testing::AssertionResult testParse(std::istream& in) {
+        std::stringstream input(kXmlPreamble);
+        input << "<resources>" << std::endl
+              << in.rdbuf() << std::endl
+              << "</resources>" << std::endl;
+        ResourceParser parser(mTable, Source{ "test" }, {},
+                              std::make_shared<SourceXmlPullParser>(input));
+        if (parser.parse()) {
+            return ::testing::AssertionSuccess();
+        }
+        return ::testing::AssertionFailure();
+    }
+
+    template <typename T>
+    const T* findResource(const ResourceNameRef& name, const ConfigDescription& config) {
+        using std::begin;
+        using std::end;
+
+        const ResourceTableType* type;
+        const ResourceEntry* entry;
+        std::tie(type, entry) = mTable->findResource(name);
+        if (!type || !entry) {
+            return nullptr;
+        }
+
+        for (const auto& configValue : entry->values) {
+            if (configValue.config == config) {
+                return dynamic_cast<const T*>(configValue.value.get());
+            }
+        }
+        return nullptr;
+    }
+
+    template <typename T>
+    const T* findResource(const ResourceNameRef& name) {
+        return findResource<T>(name, {});
+    }
+
+    std::shared_ptr<ResourceTable> mTable;
+};
+
+TEST_F(ResourceParserTest, FailToParseWithNoRootResourcesElement) {
+    std::stringstream input(kXmlPreamble);
+    input << "<attr name=\"foo\"/>" << std::endl;
+    ResourceParser parser(mTable, {}, {}, std::make_shared<SourceXmlPullParser>(input));
+    ASSERT_FALSE(parser.parse());
+}
+
+TEST_F(ResourceParserTest, ParseQuotedString) {
+    std::stringstream input("<string name=\"foo\">   \"  hey there \" </string>");
+    ASSERT_TRUE(testParse(input));
+
+    const String* str = findResource<String>(ResourceName{
+            u"android", ResourceType::kString, u"foo"});
+    ASSERT_NE(nullptr, str);
+    EXPECT_EQ(std::u16string(u"  hey there "), *str->value);
+}
+
+TEST_F(ResourceParserTest, ParseEscapedString) {
+    std::stringstream input("<string name=\"foo\">\\?123</string>");
+    ASSERT_TRUE(testParse(input));
+
+    const String* str = findResource<String>(ResourceName{
+            u"android", ResourceType::kString, u"foo" });
+    ASSERT_NE(nullptr, str);
+    EXPECT_EQ(std::u16string(u"?123"), *str->value);
+}
+
+TEST_F(ResourceParserTest, ParseAttr) {
+    std::stringstream input;
+    input << "<attr name=\"foo\" format=\"string\"/>" << std::endl
+          << "<attr name=\"bar\"/>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Attribute* attr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"foo"});
+    EXPECT_NE(nullptr, attr);
+    EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->typeMask);
+
+    attr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"bar"});
+    EXPECT_NE(nullptr, attr);
+    EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_ANY), attr->typeMask);
+}
+
+TEST_F(ResourceParserTest, ParseUseAndDeclOfAttr) {
+    std::stringstream input;
+    input << "<declare-styleable name=\"Styleable\">" << std::endl
+          << "  <attr name=\"foo\" />" << std::endl
+          << "</declare-styleable>" << std::endl
+          << "<attr name=\"foo\" format=\"string\"/>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Attribute* attr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"foo"});
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_STRING), attr->typeMask);
+}
+
+TEST_F(ResourceParserTest, ParseDoubleUseOfAttr) {
+    std::stringstream input;
+    input << "<declare-styleable name=\"Theme\">" << std::endl
+          << "  <attr name=\"foo\" />" << std::endl
+          << "</declare-styleable>" << std::endl
+          << "<declare-styleable name=\"Window\">" << std::endl
+          << "  <attr name=\"foo\" format=\"boolean\"/>" << std::endl
+          << "</declare-styleable>" << std::endl;
+
+    ASSERT_TRUE(testParse(input));
+
+    const Attribute* attr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"foo"});
+    ASSERT_NE(nullptr, attr);
+    EXPECT_EQ(uint32_t(android::ResTable_map::TYPE_BOOLEAN), attr->typeMask);
+}
+
+TEST_F(ResourceParserTest, ParseEnumAttr) {
+    std::stringstream input;
+    input << "<attr name=\"foo\">" << std::endl
+          << "  <enum name=\"bar\" value=\"0\"/>" << std::endl
+          << "  <enum name=\"bat\" value=\"1\"/>" << std::endl
+          << "  <enum name=\"baz\" value=\"2\"/>" << std::endl
+          << "</attr>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Attribute* enumAttr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"foo"});
+    ASSERT_NE(enumAttr, nullptr);
+    EXPECT_EQ(enumAttr->typeMask, android::ResTable_map::TYPE_ENUM);
+    ASSERT_EQ(enumAttr->symbols.size(), 3u);
+
+    EXPECT_EQ(enumAttr->symbols[0].symbol.name.entry, u"bar");
+    EXPECT_EQ(enumAttr->symbols[0].value, 0u);
+
+    EXPECT_EQ(enumAttr->symbols[1].symbol.name.entry, u"bat");
+    EXPECT_EQ(enumAttr->symbols[1].value, 1u);
+
+    EXPECT_EQ(enumAttr->symbols[2].symbol.name.entry, u"baz");
+    EXPECT_EQ(enumAttr->symbols[2].value, 2u);
+}
+
+TEST_F(ResourceParserTest, ParseFlagAttr) {
+    std::stringstream input;
+    input << "<attr name=\"foo\">" << std::endl
+          << "  <flag name=\"bar\" value=\"0\"/>" << std::endl
+          << "  <flag name=\"bat\" value=\"1\"/>" << std::endl
+          << "  <flag name=\"baz\" value=\"2\"/>" << std::endl
+          << "</attr>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Attribute* flagAttr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"foo"});
+    ASSERT_NE(flagAttr, nullptr);
+    EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS);
+    ASSERT_EQ(flagAttr->symbols.size(), 3u);
+
+    EXPECT_EQ(flagAttr->symbols[0].symbol.name.entry, u"bar");
+    EXPECT_EQ(flagAttr->symbols[0].value, 0u);
+
+    EXPECT_EQ(flagAttr->symbols[1].symbol.name.entry, u"bat");
+    EXPECT_EQ(flagAttr->symbols[1].value, 1u);
+
+    EXPECT_EQ(flagAttr->symbols[2].symbol.name.entry, u"baz");
+    EXPECT_EQ(flagAttr->symbols[2].value, 2u);
+
+    std::unique_ptr<BinaryPrimitive> flagValue =
+            ResourceParser::tryParseFlagSymbol(*flagAttr, u"baz|bat");
+    ASSERT_NE(flagValue, nullptr);
+    EXPECT_EQ(flagValue->value.data, 1u | 2u);
+}
+
+TEST_F(ResourceParserTest, FailToParseEnumAttrWithNonUniqueKeys) {
+    std::stringstream input;
+    input << "<attr name=\"foo\">" << std::endl
+          << "  <enum name=\"bar\" value=\"0\"/>" << std::endl
+          << "  <enum name=\"bat\" value=\"1\"/>" << std::endl
+          << "  <enum name=\"bat\" value=\"2\"/>" << std::endl
+          << "</attr>" << std::endl;
+    ASSERT_FALSE(testParse(input));
+}
+
+TEST_F(ResourceParserTest, ParseStyle) {
+    std::stringstream input;
+    input << "<style name=\"foo\" parent=\"fu\">" << std::endl
+          << "  <item name=\"bar\">#ffffffff</item>" << std::endl
+          << "  <item name=\"bat\">@string/hey</item>" << std::endl
+          << "  <item name=\"baz\"><b>hey</b></item>" << std::endl
+          << "</style>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Style* style = findResource<Style>(ResourceName{
+            u"android", ResourceType::kStyle, u"foo"});
+    ASSERT_NE(style, nullptr);
+    EXPECT_EQ(ResourceNameRef(u"android", ResourceType::kStyle, u"fu"), style->parent.name);
+    ASSERT_EQ(style->entries.size(), 3u);
+
+    EXPECT_EQ(style->entries[0].key.name,
+              (ResourceName{ u"android", ResourceType::kAttr, u"bar" }));
+    EXPECT_EQ(style->entries[1].key.name,
+              (ResourceName{ u"android", ResourceType::kAttr, u"bat" }));
+    EXPECT_EQ(style->entries[2].key.name,
+              (ResourceName{ u"android", ResourceType::kAttr, u"baz" }));
+}
+
+TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) {
+    std::stringstream input;
+    input << "<string name=\"foo\">@+id/bar</string>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Id* id = findResource<Id>(ResourceName{ u"android", ResourceType::kId, u"bar"});
+    ASSERT_NE(id, nullptr);
+}
+
+TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) {
+    std::stringstream input;
+    input << "<declare-styleable name=\"foo\">" << std::endl
+          << "  <attr name=\"bar\" />" << std::endl
+          << "  <attr name=\"bat\" format=\"string|reference\"/>" << std::endl
+          << "</declare-styleable>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Attribute* attr = findResource<Attribute>(ResourceName{
+            u"android", ResourceType::kAttr, u"bar"});
+    ASSERT_NE(attr, nullptr);
+    EXPECT_TRUE(attr->isWeak());
+
+    attr = findResource<Attribute>(ResourceName{ u"android", ResourceType::kAttr, u"bat"});
+    ASSERT_NE(attr, nullptr);
+    EXPECT_TRUE(attr->isWeak());
+
+    const Styleable* styleable = findResource<Styleable>(ResourceName{
+            u"android", ResourceType::kStyleable, u"foo" });
+    ASSERT_NE(styleable, nullptr);
+    ASSERT_EQ(2u, styleable->entries.size());
+
+    EXPECT_EQ((ResourceName{u"android", ResourceType::kAttr, u"bar"}), styleable->entries[0].name);
+    EXPECT_EQ((ResourceName{u"android", ResourceType::kAttr, u"bat"}), styleable->entries[1].name);
+}
+
+TEST_F(ResourceParserTest, ParseArray) {
+    std::stringstream input;
+    input << "<array name=\"foo\">" << std::endl
+          << "  <item>@string/ref</item>" << std::endl
+          << "  <item>hey</item>" << std::endl
+          << "  <item>23</item>" << std::endl
+          << "</array>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const Array* array = findResource<Array>(ResourceName{
+            u"android", ResourceType::kArray, u"foo" });
+    ASSERT_NE(array, nullptr);
+    ASSERT_EQ(3u, array->items.size());
+
+    EXPECT_NE(nullptr, dynamic_cast<const Reference*>(array->items[0].get()));
+    EXPECT_NE(nullptr, dynamic_cast<const String*>(array->items[1].get()));
+    EXPECT_NE(nullptr, dynamic_cast<const BinaryPrimitive*>(array->items[2].get()));
+}
+
+TEST_F(ResourceParserTest, ParsePlural) {
+    std::stringstream input;
+    input << "<plurals name=\"foo\">" << std::endl
+          << "  <item quantity=\"other\">apples</item>" << std::endl
+          << "  <item quantity=\"one\">apple</item>" << std::endl
+          << "</plurals>" << std::endl
+          << std::endl;
+    ASSERT_TRUE(testParse(input));
+}
+
+TEST_F(ResourceParserTest, ParseCommentsWithResource) {
+    std::stringstream input;
+    input << "<!-- This is a comment -->" << std::endl
+          << "<string name=\"foo\">Hi</string>" << std::endl;
+    ASSERT_TRUE(testParse(input));
+
+    const ResourceTableType* type;
+    const ResourceEntry* entry;
+    std::tie(type, entry) = mTable->findResource(ResourceName{
+            u"android", ResourceType::kString, u"foo"});
+    ASSERT_NE(type, nullptr);
+    ASSERT_NE(entry, nullptr);
+    ASSERT_FALSE(entry->values.empty());
+    EXPECT_EQ(entry->values.front().comment, u"This is a comment");
+}
+
+/*
+ * Declaring an ID as public should not require a separate definition
+ * (as an ID has no value).
+ */
+TEST_F(ResourceParserTest, ParsePublicIdAsDefinition) {
+    std::stringstream input("<public type=\"id\" name=\"foo\"/>");
+    ASSERT_TRUE(testParse(input));
+
+    const Id* id = findResource<Id>(ResourceName{ u"android", ResourceType::kId, u"foo" });
+    ASSERT_NE(nullptr, id);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
new file mode 100644
index 0000000..794090d0
--- /dev/null
+++ b/tools/aapt2/ResourceTable.cpp
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigDescription.h"
+#include "Logger.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <androidfw/ResourceTypes.h>
+#include <memory>
+#include <string>
+#include <tuple>
+
+namespace aapt {
+
+static bool compareConfigs(const ResourceConfigValue& lhs, const ConfigDescription& rhs) {
+    return lhs.config < rhs;
+}
+
+static bool lessThanType(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
+    return lhs->type < rhs;
+}
+
+static bool lessThanEntry(const std::unique_ptr<ResourceEntry>& lhs, const StringPiece16& rhs) {
+    return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
+}
+
+ResourceTable::ResourceTable() : mPackageId(kUnsetPackageId) {
+}
+
+std::unique_ptr<ResourceTableType>& ResourceTable::findOrCreateType(ResourceType type) {
+    auto last = mTypes.end();
+    auto iter = std::lower_bound(mTypes.begin(), last, type, lessThanType);
+    if (iter != last) {
+        if ((*iter)->type == type) {
+            return *iter;
+        }
+    }
+    return *mTypes.emplace(iter, new ResourceTableType{ type });
+}
+
+std::unique_ptr<ResourceEntry>& ResourceTable::findOrCreateEntry(
+        std::unique_ptr<ResourceTableType>& type, const StringPiece16& name) {
+    auto last = type->entries.end();
+    auto iter = std::lower_bound(type->entries.begin(), last, name, lessThanEntry);
+    if (iter != last) {
+        if (name == (*iter)->name) {
+            return *iter;
+        }
+    }
+    return *type->entries.emplace(iter, new ResourceEntry{ name });
+}
+
+struct IsAttributeVisitor : ConstValueVisitor {
+    bool isAttribute = false;
+
+    void visit(const Attribute&, ValueVisitorArgs&) override {
+        isAttribute = true;
+    }
+
+    operator bool() {
+        return isAttribute;
+    }
+};
+
+/**
+ * The default handler for collisions. A return value of -1 means keep the
+ * existing value, 0 means fail, and +1 means take the incoming value.
+ */
+static int defaultCollisionHandler(const Value& existing, const Value& incoming) {
+    IsAttributeVisitor existingIsAttr, incomingIsAttr;
+    existing.accept(existingIsAttr, {});
+    incoming.accept(incomingIsAttr, {});
+
+    if (!incomingIsAttr) {
+        if (incoming.isWeak()) {
+            // We're trying to add a weak resource but a resource
+            // already exists. Keep the existing.
+            return -1;
+        } else if (existing.isWeak()) {
+            // Override the weak resource with the new strong resource.
+            return 1;
+        }
+        // The existing and incoming values are strong, this is an error
+        // if the values are not both attributes.
+        return 0;
+    }
+
+    if (!existingIsAttr) {
+        if (existing.isWeak()) {
+            // The existing value is not an attribute and it is weak,
+            // so take the incoming attribute value.
+            return 1;
+        }
+        // The existing value is not an attribute and it is strong,
+        // so the incoming attribute value is an error.
+        return 0;
+    }
+
+    //
+    // Attribute specific handling. At this point we know both
+    // values are attributes. Since we can declare and define
+    // attributes all-over, we do special handling to see
+    // which definition sticks.
+    //
+    const Attribute& existingAttr = static_cast<const Attribute&>(existing);
+    const Attribute& incomingAttr = static_cast<const Attribute&>(incoming);
+    if (existingAttr.typeMask == incomingAttr.typeMask) {
+        // The two attributes are both DECLs, but they are plain attributes
+        // with the same formats.
+        // Keep the strongest one.
+        return existingAttr.isWeak() ? 1 : -1;
+    }
+
+    if (existingAttr.isWeak() && existingAttr.typeMask == android::ResTable_map::TYPE_ANY) {
+        // Any incoming attribute is better than this.
+        return 1;
+    }
+
+    if (incomingAttr.isWeak() && incomingAttr.typeMask == android::ResTable_map::TYPE_ANY) {
+        // The incoming attribute may be a USE instead of a DECL.
+        // Keep the existing attribute.
+        return -1;
+    }
+    return 0;
+}
+
+static constexpr const char16_t* kValidNameChars = u"._-";
+
+bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId,
+        const ConfigDescription& config, const SourceLine& source,
+        std::unique_ptr<Value> value) {
+    if (!name.package.empty() && name.package != mPackage) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has incompatible package. Must be '"
+                << mPackage
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, kValidNameChars);
+    if (badCharIter != name.entry.end()) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has invalid entry name '"
+                << name.entry
+                << "'. Invalid character '"
+                << StringPiece16(badCharIter, 1)
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
+    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
+            type->typeId != resId.typeId()) {
+        Logger::error(source)
+                << "trying to add resource '"
+                << name
+                << "' with ID "
+                << resId
+                << " but type '"
+                << type->type
+                << "' already has ID "
+                << std::hex << type->typeId << std::dec
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
+    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
+            entry->entryId != resId.entryId()) {
+        Logger::error(source)
+                << "trying to add resource '"
+                << name
+                << "' with ID "
+                << resId
+                << " but resource already has ID "
+                << ResourceId(mPackageId, type->typeId, entry->entryId)
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    const auto endIter = std::end(entry->values);
+    auto iter = std::lower_bound(std::begin(entry->values), endIter, config, compareConfigs);
+    if (iter == endIter || iter->config != config) {
+        // This resource did not exist before, add it.
+        entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) });
+    } else {
+        int collisionResult = defaultCollisionHandler(*iter->value, *value);
+        if (collisionResult > 0) {
+            // Take the incoming value.
+            *iter = ResourceConfigValue{ config, source, {}, std::move(value) };
+        } else if (collisionResult == 0) {
+            Logger::error(source)
+                    << "duplicate value for resource '" << name << "' "
+                    << "with config '" << iter->config << "'."
+                    << std::endl;
+
+            Logger::error(iter->source)
+                    << "resource previously defined here."
+                    << std::endl;
+            return false;
+        }
+    }
+
+    if (resId.isValid()) {
+        type->typeId = resId.typeId();
+        entry->entryId = resId.entryId();
+    }
+    return true;
+}
+
+bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config,
+                                const SourceLine& source, std::unique_ptr<Value> value) {
+    return addResource(name, ResourceId{}, config, source, std::move(value));
+}
+
+bool ResourceTable::markPublic(const ResourceNameRef& name, const ResourceId resId,
+                               const SourceLine& source) {
+    if (!name.package.empty() && name.package != mPackage) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has incompatible package. Must be '"
+                << mPackage
+                << "'."
+            << std::endl;
+        return false;
+    }
+
+    auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, kValidNameChars);
+    if (badCharIter != name.entry.end()) {
+        Logger::error(source)
+                << "resource '"
+                << name
+                << "' has invalid entry name '"
+                << name.entry
+                << "'. Invalid character '"
+                << StringPiece16(badCharIter, 1)
+                << "'."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceTableType>& type = findOrCreateType(name.type);
+    if (resId.isValid() && type->typeId != ResourceTableType::kUnsetTypeId &&
+            type->typeId != resId.typeId()) {
+        Logger::error(source)
+                << "trying to make resource '"
+                << name
+                << "' public with ID "
+                << resId
+                << " but type '"
+                << type->type
+                << "' already has ID "
+                << std::hex << type->typeId << std::dec
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    std::unique_ptr<ResourceEntry>& entry = findOrCreateEntry(type, name.entry);
+    if (resId.isValid() && entry->entryId != ResourceEntry::kUnsetEntryId &&
+            entry->entryId != resId.entryId()) {
+        Logger::error(source)
+                << "trying to make resource '"
+                << name
+                << "' public with ID "
+                << resId
+                << " but resource already has ID "
+                << ResourceId(mPackageId, type->typeId, entry->entryId)
+                << "."
+                << std::endl;
+        return false;
+    }
+
+    type->publicStatus.isPublic = true;
+    entry->publicStatus.isPublic = true;
+
+    if (resId.isValid()) {
+        type->typeId = resId.typeId();
+        entry->entryId = resId.entryId();
+    }
+
+    if (entry->values.empty()) {
+        entry->values.push_back(ResourceConfigValue{ {}, source, {},
+                                    util::make_unique<Sentinel>() });
+    }
+    return true;
+}
+
+std::tuple<const ResourceTableType*, const ResourceEntry*>
+ResourceTable::findResource(const ResourceNameRef& name) const {
+    if (name.package != mPackage) {
+        return {};
+    }
+
+    auto iter = std::lower_bound(mTypes.begin(), mTypes.end(), name.type, lessThanType);
+    if (iter == mTypes.end() || (*iter)->type != name.type) {
+        return {};
+    }
+
+    const std::unique_ptr<ResourceTableType>& type = *iter;
+    auto iter2 = std::lower_bound(type->entries.begin(), type->entries.end(), name.entry,
+                                  lessThanEntry);
+    if (iter2 == type->entries.end() || name.entry != (*iter2)->name) {
+        return {};
+    }
+    return std::make_tuple(iter->get(), iter2->get());
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
new file mode 100644
index 0000000..57b5213
--- /dev/null
+++ b/tools/aapt2/ResourceTable.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RESOURCE_TABLE_H
+#define AAPT_RESOURCE_TABLE_H
+
+#include "ConfigDescription.h"
+#include "Resource.h"
+#include "ResourceValues.h"
+#include "Source.h"
+#include "StringPool.h"
+
+#include <memory>
+#include <string>
+#include <tuple>
+#include <vector>
+
+namespace aapt {
+
+/**
+ * The Public status of a resource.
+ */
+struct Public {
+    bool isPublic = false;
+    std::u16string comment;
+};
+
+/**
+ * The resource value for a specific configuration.
+ */
+struct ResourceConfigValue {
+    ConfigDescription config;
+    SourceLine source;
+    std::u16string comment;
+    std::unique_ptr<Value> value;
+};
+
+/**
+ * Represents a resource entry, which may have
+ * varying values for each defined configuration.
+ */
+struct ResourceEntry {
+    enum {
+        kUnsetEntryId = 0xffffffffu
+    };
+
+    /**
+     * The name of the resource. Immutable, as
+     * this determines the order of this resource
+     * when doing lookups.
+     */
+    const std::u16string name;
+
+    /**
+     * The entry ID for this resource.
+     */
+    size_t entryId;
+
+    /**
+     * Whether this resource is public (and must maintain the same
+     * entry ID across builds).
+     */
+    Public publicStatus;
+
+    /**
+     * The resource's values for each configuration.
+     */
+    std::vector<ResourceConfigValue> values;
+
+    inline ResourceEntry(const StringPiece16& _name);
+    inline ResourceEntry(const ResourceEntry* rhs);
+};
+
+/**
+ * Represents a resource type, which holds entries defined
+ * for this type.
+ */
+struct ResourceTableType {
+    enum {
+        kUnsetTypeId = 0xffffffffu
+    };
+
+    /**
+     * The logical type of resource (string, drawable, layout, etc.).
+     */
+    const ResourceType type;
+
+    /**
+     * The type ID for this resource.
+     */
+    size_t typeId;
+
+    /**
+     * Whether this type is public (and must maintain the same
+     * type ID across builds).
+     */
+    Public publicStatus;
+
+    /**
+     * List of resources for this type.
+     */
+    std::vector<std::unique_ptr<ResourceEntry>> entries;
+
+    ResourceTableType(const ResourceType _type);
+    ResourceTableType(const ResourceTableType* rhs);
+};
+
+/**
+ * The container and index for all resources defined for an app. This gets
+ * flattened into a binary resource table (resources.arsc).
+ */
+class ResourceTable {
+public:
+    using iterator = std::vector<std::unique_ptr<ResourceTableType>>::iterator;
+    using const_iterator = std::vector<std::unique_ptr<ResourceTableType>>::const_iterator;
+
+    enum {
+        kUnsetPackageId = 0xffffffff
+    };
+
+    ResourceTable();
+
+    size_t getPackageId() const;
+    void setPackageId(size_t packageId);
+
+    const std::u16string& getPackage() const;
+    void setPackage(const StringPiece16& package);
+
+    bool addResource(const ResourceNameRef& name, const ConfigDescription& config,
+                     const SourceLine& source, std::unique_ptr<Value> value);
+
+    bool addResource(const ResourceNameRef& name, const ResourceId resId,
+                     const ConfigDescription& config, const SourceLine& source,
+                     std::unique_ptr<Value> value);
+
+    bool markPublic(const ResourceNameRef& name, const ResourceId resId, const SourceLine& source);
+
+    /**
+     * Returns the string pool used by this ResourceTable.
+     * Values that reference strings should use this pool to create
+     * their strings.
+     */
+    StringPool& getValueStringPool();
+    const StringPool& getValueStringPool() const;
+
+    std::tuple<const ResourceTableType*, const ResourceEntry*>
+    findResource(const ResourceNameRef& name) const;
+
+    iterator begin();
+    iterator end();
+    const_iterator begin() const;
+    const_iterator end() const;
+
+private:
+    std::unique_ptr<ResourceTableType>& findOrCreateType(ResourceType type);
+    std::unique_ptr<ResourceEntry>& findOrCreateEntry(std::unique_ptr<ResourceTableType>& type,
+                                                      const StringPiece16& name);
+
+    std::u16string mPackage;
+    size_t mPackageId;
+
+    // StringPool must come before mTypes so that it is destroyed after.
+    // When StringPool references are destroyed (as they will be when mTypes
+    // is destroyed), they decrement a refCount, which would cause invalid
+    // memory access if the pool was already destroyed.
+    StringPool mValuePool;
+
+    std::vector<std::unique_ptr<ResourceTableType>> mTypes;
+};
+
+//
+// ResourceEntry implementation.
+//
+
+inline ResourceEntry::ResourceEntry(const StringPiece16& _name) :
+        name(_name.toString()), entryId(kUnsetEntryId) {
+}
+
+inline ResourceEntry::ResourceEntry(const ResourceEntry* rhs) :
+        name(rhs->name), entryId(rhs->entryId), publicStatus(rhs->publicStatus) {
+}
+
+//
+// ResourceTableType implementation.
+//
+
+inline ResourceTableType::ResourceTableType(const ResourceType _type) :
+        type(_type), typeId(kUnsetTypeId) {
+}
+
+inline ResourceTableType::ResourceTableType(const ResourceTableType* rhs) :
+        type(rhs->type), typeId(rhs->typeId), publicStatus(rhs->publicStatus) {
+}
+
+//
+// ResourceTable implementation.
+//
+
+inline StringPool& ResourceTable::getValueStringPool() {
+    return mValuePool;
+}
+
+inline const StringPool& ResourceTable::getValueStringPool() const {
+    return mValuePool;
+}
+
+inline ResourceTable::iterator ResourceTable::begin() {
+    return mTypes.begin();
+}
+
+inline ResourceTable::iterator ResourceTable::end() {
+    return mTypes.end();
+}
+
+inline ResourceTable::const_iterator ResourceTable::begin() const {
+    return mTypes.begin();
+}
+
+inline ResourceTable::const_iterator ResourceTable::end() const {
+    return mTypes.end();
+}
+
+inline const std::u16string& ResourceTable::getPackage() const {
+    return mPackage;
+}
+
+inline size_t ResourceTable::getPackageId() const {
+    return mPackageId;
+}
+
+inline void ResourceTable::setPackage(const StringPiece16& package) {
+    mPackage = package.toString();
+}
+
+inline void ResourceTable::setPackageId(size_t packageId) {
+    mPackageId = packageId;
+}
+
+} // namespace aapt
+
+#endif // AAPT_RESOURCE_TABLE_H
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
new file mode 100644
index 0000000..785ea15
--- /dev/null
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <gtest/gtest.h>
+#include <ostream>
+#include <string>
+
+namespace aapt {
+
+struct TestValue : public Value {
+    std::u16string value;
+
+    TestValue(StringPiece16 str) : value(str.toString()) {
+    }
+
+    TestValue* clone() const override {
+        return new TestValue(value);
+    }
+
+    void print(std::ostream& out) const override {
+        out << "(test) " << value;
+    }
+
+    virtual void accept(ValueVisitor&, ValueVisitorArgs&&) override {}
+    virtual void accept(ConstValueVisitor&, ValueVisitorArgs&&) const override {}
+};
+
+struct TestWeakValue : public Value {
+    bool isWeak() const override {
+        return true;
+    }
+
+    TestWeakValue* clone() const override {
+        return new TestWeakValue();
+    }
+
+    void print(std::ostream& out) const override {
+        out << "(test) [weak]";
+    }
+
+    virtual void accept(ValueVisitor&, ValueVisitorArgs&&) override {}
+    virtual void accept(ConstValueVisitor&, ValueVisitorArgs&&) const override {}
+};
+
+TEST(ResourceTableTest, FailToAddResourceWithBadName) {
+    ResourceTable table;
+    table.setPackage(u"android");
+
+    EXPECT_FALSE(table.addResource(
+            ResourceNameRef{ u"android", ResourceType::kId, u"hey,there" },
+            {}, SourceLine{ "test.xml", 21 },
+            util::make_unique<TestValue>(u"rawValue")));
+
+    EXPECT_FALSE(table.addResource(
+            ResourceNameRef{ u"android", ResourceType::kId, u"hey:there" },
+            {}, SourceLine{ "test.xml", 21 },
+            util::make_unique<TestValue>(u"rawValue")));
+}
+
+TEST(ResourceTableTest, AddOneResource) {
+    const std::u16string kAndroidPackage = u"android";
+
+    ResourceTable table;
+    table.setPackage(kAndroidPackage);
+
+    const ResourceName name = { kAndroidPackage, ResourceType::kAttr, u"id" };
+
+    EXPECT_TRUE(table.addResource(name, {}, SourceLine{ "test/path/file.xml", 23 },
+                                  util::make_unique<TestValue>(u"rawValue")));
+
+    const ResourceTableType* type;
+    const ResourceEntry* entry;
+    std::tie(type, entry) = table.findResource(name);
+    ASSERT_NE(nullptr, type);
+    ASSERT_NE(nullptr, entry);
+    EXPECT_EQ(name.entry, entry->name);
+
+    ASSERT_NE(std::end(entry->values),
+              std::find_if(std::begin(entry->values), std::end(entry->values),
+                      [](const ResourceConfigValue& val) -> bool {
+                          return val.config == ConfigDescription{};
+                      }));
+}
+
+TEST(ResourceTableTest, AddMultipleResources) {
+    const std::u16string kAndroidPackage = u"android";
+    ResourceTable table;
+    table.setPackage(kAndroidPackage);
+
+    ConfigDescription config;
+    ConfigDescription languageConfig;
+    memcpy(languageConfig.language, "pl", sizeof(languageConfig.language));
+
+    EXPECT_TRUE(table.addResource(
+            ResourceName{ kAndroidPackage, ResourceType::kAttr, u"layout_width" },
+            config, SourceLine{ "test/path/file.xml", 10 },
+            util::make_unique<TestValue>(u"rawValue")));
+
+    EXPECT_TRUE(table.addResource(
+            ResourceName{ kAndroidPackage, ResourceType::kAttr, u"id" },
+            config, SourceLine{ "test/path/file.xml", 12 },
+            util::make_unique<TestValue>(u"rawValue")));
+
+    EXPECT_TRUE(table.addResource(
+            ResourceName{ kAndroidPackage, ResourceType::kString, u"ok" },
+            config, SourceLine{ "test/path/file.xml", 14 },
+            util::make_unique<TestValue>(u"Ok")));
+
+    EXPECT_TRUE(table.addResource(
+            ResourceName{ kAndroidPackage, ResourceType::kString, u"ok" },
+            languageConfig, SourceLine{ "test/path/file.xml", 20 },
+            util::make_unique<TestValue>(u"Tak")));
+
+    const auto endTypeIter = std::end(table);
+    auto typeIter = std::begin(table);
+
+    ASSERT_NE(endTypeIter, typeIter);
+    EXPECT_EQ(ResourceType::kAttr, (*typeIter)->type);
+
+    {
+        const std::unique_ptr<ResourceTableType>& type = *typeIter;
+        const auto endEntryIter = std::end(type->entries);
+        auto entryIter = std::begin(type->entries);
+        ASSERT_NE(endEntryIter, entryIter);
+        EXPECT_EQ(std::u16string(u"id"), (*entryIter)->name);
+
+        ++entryIter;
+        ASSERT_NE(endEntryIter, entryIter);
+        EXPECT_EQ(std::u16string(u"layout_width"), (*entryIter)->name);
+
+        ++entryIter;
+        ASSERT_EQ(endEntryIter, entryIter);
+    }
+
+    ++typeIter;
+    ASSERT_NE(endTypeIter, typeIter);
+    EXPECT_EQ(ResourceType::kString, (*typeIter)->type);
+
+    {
+        const std::unique_ptr<ResourceTableType>& type = *typeIter;
+        const auto endEntryIter = std::end(type->entries);
+        auto entryIter = std::begin(type->entries);
+        ASSERT_NE(endEntryIter, entryIter);
+        EXPECT_EQ(std::u16string(u"ok"), (*entryIter)->name);
+
+        {
+            const std::unique_ptr<ResourceEntry>& entry = *entryIter;
+            const auto endConfigIter = std::end(entry->values);
+            auto configIter = std::begin(entry->values);
+
+            ASSERT_NE(endConfigIter, configIter);
+            EXPECT_EQ(config, configIter->config);
+            const TestValue* value =
+                    dynamic_cast<const TestValue*>(configIter->value.get());
+            ASSERT_NE(nullptr, value);
+            EXPECT_EQ(std::u16string(u"Ok"), value->value);
+
+            ++configIter;
+            ASSERT_NE(endConfigIter, configIter);
+            EXPECT_EQ(languageConfig, configIter->config);
+            EXPECT_NE(nullptr, configIter->value);
+
+            value = dynamic_cast<const TestValue*>(configIter->value.get());
+            ASSERT_NE(nullptr, value);
+            EXPECT_EQ(std::u16string(u"Tak"), value->value);
+
+            ++configIter;
+            EXPECT_EQ(endConfigIter, configIter);
+        }
+
+        ++entryIter;
+        ASSERT_EQ(endEntryIter, entryIter);
+    }
+
+    ++typeIter;
+    EXPECT_EQ(endTypeIter, typeIter);
+}
+
+TEST(ResourceTableTest, OverrideWeakResourceValue) {
+    const std::u16string kAndroid = u"android";
+
+    ResourceTable table;
+    table.setPackage(kAndroid);
+    table.setPackageId(0x01);
+
+    ASSERT_TRUE(table.addResource(
+            ResourceName{ kAndroid, ResourceType::kAttr, u"foo" },
+            {}, {}, util::make_unique<TestWeakValue>()));
+
+    const ResourceTableType* type;
+    const ResourceEntry* entry;
+    std::tie(type, entry) = table.findResource(
+            ResourceNameRef{ kAndroid, ResourceType::kAttr, u"foo" });
+    ASSERT_NE(nullptr, type);
+    ASSERT_NE(nullptr, entry);
+    ASSERT_EQ(entry->values.size(), 1u);
+    EXPECT_TRUE(entry->values.front().value->isWeak());
+
+    ASSERT_TRUE(table.addResource(ResourceName{ kAndroid, ResourceType::kAttr, u"foo" }, {}, {},
+                                  util::make_unique<TestValue>(u"bar")));
+
+    std::tie(type, entry) = table.findResource(
+            ResourceNameRef{ kAndroid, ResourceType::kAttr, u"foo" });
+    ASSERT_NE(nullptr, type);
+    ASSERT_NE(nullptr, entry);
+    ASSERT_EQ(entry->values.size(), 1u);
+    EXPECT_FALSE(entry->values.front().value->isWeak());
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ResourceTypeExtensions.h b/tools/aapt2/ResourceTypeExtensions.h
new file mode 100644
index 0000000..60e225e
--- /dev/null
+++ b/tools/aapt2/ResourceTypeExtensions.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RESOURCE_TYPE_EXTENSIONS_H
+#define AAPT_RESOURCE_TYPE_EXTENSIONS_H
+
+#include <androidfw/ResourceTypes.h>
+
+namespace aapt {
+
+/**
+ * New android::ResChunk_header types defined
+ * for AAPT to use.
+ *
+ * TODO(adamlesinski): Consider reserving these
+ * enums in androidfw/ResourceTypes.h to avoid
+ * future collisions.
+ */
+enum {
+    /**
+     * A chunk that holds the string pool
+     * for source entries (path/to/source:line).
+     */
+    RES_TABLE_SOURCE_POOL_TYPE = 0x000e,
+
+    /**
+     * A chunk holding names of externally
+     * defined symbols and offsets to where
+     * they are referenced in the table.
+     */
+    RES_TABLE_SYMBOL_TABLE_TYPE = 0x000f,
+};
+
+/**
+ * New resource types that are meant to only be used
+ * by AAPT and will not end up on the device.
+ */
+struct ExtendedTypes {
+    enum {
+        /**
+         * A sentinel value used when a resource is defined as
+         * public but it has no defined value yet. If we don't
+         * flatten it with some value, we will lose its name.
+         */
+        TYPE_SENTINEL = 0xff,
+
+        /**
+         * A raw string value that hasn't had its escape sequences
+         * processed nor whitespace removed.
+         */
+        TYPE_RAW_STRING = 0xfe
+    };
+};
+
+/**
+ * A chunk with type RES_TABLE_SYMBOL_TABLE_TYPE.
+ * Following the header are count number of SymbolTable_entry
+ * structures, followed by an android::ResStringPool_header.
+ */
+struct SymbolTable_header {
+    android::ResChunk_header header;
+
+    /**
+     * Number of SymbolTable_entry structures following
+     * this header.
+     */
+    uint32_t count;
+};
+
+struct SymbolTable_entry {
+    /**
+     * Offset from the beginning of the resource table
+     * where the symbol entry is referenced.
+     */
+    uint32_t offset;
+
+    /**
+     * The index into the string pool where the name of this
+     * symbol exists.
+     */
+    uint32_t stringIndex;
+};
+
+/**
+ * A structure representing the source of a resourc entry.
+ * Appears after an android::ResTable_entry or android::ResTable_map_entry.
+ *
+ * TODO(adamlesinski): This causes some issues when runtime code checks
+ * the size of an android::ResTable_entry. It assumes it is an
+ * android::ResTable_map_entry if the size is bigger than an android::ResTable_entry
+ * which may not be true if this structure is present.
+ */
+struct ResTable_entry_source {
+    /**
+     * Index into the source string pool.
+     */
+    uint32_t pathIndex;
+
+    /**
+     * Line number this resource was defined on.
+     */
+    uint32_t line;
+};
+
+} // namespace aapt
+
+#endif // AAPT_RESOURCE_TYPE_EXTENSIONS_H
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
new file mode 100644
index 0000000..60ef1a8
--- /dev/null
+++ b/tools/aapt2/ResourceValues.cpp
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Resource.h"
+#include "ResourceTypeExtensions.h"
+#include "ResourceValues.h"
+#include "Util.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <limits>
+
+namespace aapt {
+
+bool Value::isItem() const {
+    return false;
+}
+
+bool Value::isWeak() const {
+    return false;
+}
+
+bool Item::isItem() const {
+    return true;
+}
+
+RawString::RawString(const StringPool::Ref& ref) : value(ref) {
+}
+
+RawString* RawString::clone() const {
+    return new RawString(value);
+}
+
+bool RawString::flatten(android::Res_value& outValue) const {
+    outValue.dataType = ExtendedTypes::TYPE_RAW_STRING;
+    outValue.data = static_cast<uint32_t>(value.getIndex());
+    return true;
+}
+
+void RawString::print(std::ostream& out) const {
+    out << "(raw string) " << *value;
+}
+
+Reference::Reference() : referenceType(Reference::Type::kResource) {
+}
+
+Reference::Reference(const ResourceNameRef& n, Type t) :
+        name(n.toResourceName()), referenceType(t) {
+}
+
+Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
+}
+
+bool Reference::flatten(android::Res_value& outValue) const {
+    outValue.dataType = (referenceType == Reference::Type::kResource)
+        ? android::Res_value::TYPE_REFERENCE
+        : android::Res_value::TYPE_ATTRIBUTE;
+    outValue.data = id.id;
+    return true;
+}
+
+Reference* Reference::clone() const {
+    Reference* ref = new Reference();
+    ref->referenceType = referenceType;
+    ref->name = name;
+    ref->id = id;
+    return ref;
+}
+
+void Reference::print(std::ostream& out) const {
+    out << "(reference) ";
+    if (referenceType == Reference::Type::kResource) {
+        out << "@";
+    } else {
+        out << "?";
+    }
+
+    if (name.isValid()) {
+        out << name;
+    }
+
+    if (id.isValid() || Res_INTERNALID(id.id)) {
+        out << " " << id;
+    }
+}
+
+bool Id::isWeak() const {
+    return true;
+}
+
+bool Id::flatten(android::Res_value& out) const {
+    out.dataType = android::Res_value::TYPE_NULL;
+    out.data = android::Res_value::DATA_NULL_UNDEFINED;
+    return true;
+}
+
+Id* Id::clone() const {
+    return new Id();
+}
+
+void Id::print(std::ostream& out) const {
+    out << "(id)";
+}
+
+String::String(const StringPool::Ref& ref) : value(ref) {
+}
+
+bool String::flatten(android::Res_value& outValue) const {
+    // Verify that our StringPool index is within encodeable limits.
+    if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
+        return false;
+    }
+
+    outValue.dataType = android::Res_value::TYPE_STRING;
+    outValue.data = static_cast<uint32_t>(value.getIndex());
+    return true;
+}
+
+String* String::clone() const {
+    return new String(value);
+}
+
+void String::print(std::ostream& out) const {
+    out << "(string) \"" << *value << "\"";
+}
+
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+}
+
+bool StyledString::flatten(android::Res_value& outValue) const {
+    if (value.getIndex() > std::numeric_limits<uint32_t>::max()) {
+        return false;
+    }
+
+    outValue.dataType = android::Res_value::TYPE_STRING;
+    outValue.data = static_cast<uint32_t>(value.getIndex());
+    return true;
+}
+
+StyledString* StyledString::clone() const {
+    return new StyledString(value);
+}
+
+void StyledString::print(std::ostream& out) const {
+    out << "(styled string) \"" << *value->str << "\"";
+}
+
+FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
+}
+
+bool FileReference::flatten(android::Res_value& outValue) const {
+    if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
+        return false;
+    }
+
+    outValue.dataType = android::Res_value::TYPE_STRING;
+    outValue.data = static_cast<uint32_t>(path.getIndex());
+    return true;
+}
+
+FileReference* FileReference::clone() const {
+    return new FileReference(path);
+}
+
+void FileReference::print(std::ostream& out) const {
+    out << "(file) " << *path;
+}
+
+BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
+}
+
+bool BinaryPrimitive::flatten(android::Res_value& outValue) const {
+    outValue = value;
+    return true;
+}
+
+BinaryPrimitive* BinaryPrimitive::clone() const {
+    return new BinaryPrimitive(value);
+}
+
+void BinaryPrimitive::print(std::ostream& out) const {
+    switch (value.dataType) {
+        case android::Res_value::TYPE_NULL:
+            out << "(null)";
+            break;
+        case android::Res_value::TYPE_INT_DEC:
+            out << "(integer) " << value.data;
+            break;
+        case android::Res_value::TYPE_INT_HEX:
+            out << "(integer) " << std::hex << value.data << std::dec;
+            break;
+        case android::Res_value::TYPE_INT_BOOLEAN:
+            out << "(boolean) " << (value.data != 0 ? "true" : "false");
+            break;
+        case android::Res_value::TYPE_INT_COLOR_ARGB8:
+        case android::Res_value::TYPE_INT_COLOR_RGB8:
+        case android::Res_value::TYPE_INT_COLOR_ARGB4:
+        case android::Res_value::TYPE_INT_COLOR_RGB4:
+            out << "(color) #" << std::hex << value.data << std::dec;
+            break;
+        default:
+            out << "(unknown 0x" << std::hex << (int) value.dataType << ") 0x"
+                << std::hex << value.data << std::dec;
+            break;
+    }
+}
+
+bool Sentinel::isWeak() const {
+    return true;
+}
+
+bool Sentinel::flatten(android::Res_value& outValue) const {
+    outValue.dataType = ExtendedTypes::TYPE_SENTINEL;
+    outValue.data = 0;
+    return true;
+}
+
+Sentinel* Sentinel::clone() const {
+    return new Sentinel();
+}
+
+void Sentinel::print(std::ostream& out) const {
+    out << "(sentinel)";
+    return;
+}
+
+Attribute::Attribute(bool w, uint32_t t) : weak(w), typeMask(t) {
+}
+
+bool Attribute::isWeak() const {
+    return weak;
+}
+
+Attribute* Attribute::clone() const {
+    Attribute* attr = new Attribute(weak);
+    attr->typeMask = typeMask;
+    std::copy(symbols.begin(), symbols.end(), std::back_inserter(attr->symbols));
+    return attr;
+}
+
+void Attribute::print(std::ostream& out) const {
+    out << "(attr)";
+    if (typeMask == android::ResTable_map::TYPE_ANY) {
+        out << " any";
+        return;
+    }
+
+    bool set = false;
+    if ((typeMask & android::ResTable_map::TYPE_REFERENCE) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "reference";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_STRING) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "string";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_INTEGER) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "integer";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "boolean";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_COLOR) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "color";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_FLOAT) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "float";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_DIMENSION) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "dimension";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_FRACTION) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "fraction";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_ENUM) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "enum";
+    }
+
+    if ((typeMask & android::ResTable_map::TYPE_FLAGS) != 0) {
+        if (!set) {
+            out << " ";
+            set = true;
+        } else {
+            out << "|";
+        }
+        out << "flags";
+    }
+
+    out << " ["
+        << util::joiner(symbols.begin(), symbols.end(), ", ")
+        << "]";
+
+    if (weak) {
+        out << " [weak]";
+    }
+}
+
+static ::std::ostream& operator<<(::std::ostream& out, const Attribute::Symbol& s) {
+    return out << s.symbol.name.entry << "=" << s.value;
+}
+
+Style* Style::clone() const {
+    Style* style = new Style();
+    style->parent = parent;
+    for (auto& entry : entries) {
+        style->entries.push_back(Entry{
+                entry.key,
+                std::unique_ptr<Item>(entry.value->clone())
+        });
+    }
+    return style;
+}
+
+void Style::print(std::ostream& out) const {
+    out << "(style) ";
+    if (!parent.name.entry.empty()) {
+        out << parent.name;
+    }
+    out << " ["
+        << util::joiner(entries.begin(), entries.end(), ", ")
+        << "]";
+}
+
+static ::std::ostream& operator<<(::std::ostream& out, const Style::Entry& value) {
+    out << value.key.name << " = ";
+    value.value->print(out);
+    return out;
+}
+
+Array* Array::clone() const {
+    Array* array = new Array();
+    for (auto& item : items) {
+        array->items.emplace_back(std::unique_ptr<Item>(item->clone()));
+    }
+    return array;
+}
+
+void Array::print(std::ostream& out) const {
+    out << "(array) ["
+        << util::joiner(items.begin(), items.end(), ", ")
+        << "]";
+}
+
+Plural* Plural::clone() const {
+    Plural* p = new Plural();
+    const size_t count = values.size();
+    for (size_t i = 0; i < count; i++) {
+        if (values[i]) {
+            p->values[i] = std::unique_ptr<Item>(values[i]->clone());
+        }
+    }
+    return p;
+}
+
+void Plural::print(std::ostream& out) const {
+    out << "(plural)";
+}
+
+static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
+    return out << *item;
+}
+
+Styleable* Styleable::clone() const {
+    Styleable* styleable = new Styleable();
+    std::copy(entries.begin(), entries.end(), std::back_inserter(styleable->entries));
+    return styleable;
+}
+
+void Styleable::print(std::ostream& out) const {
+    out << "(styleable) " << " ["
+        << util::joiner(entries.begin(), entries.end(), ", ")
+        << "]";
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
new file mode 100644
index 0000000..f25bcf0
--- /dev/null
+++ b/tools/aapt2/ResourceValues.h
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_RESOURCE_VALUES_H
+#define AAPT_RESOURCE_VALUES_H
+
+#include "Resource.h"
+#include "StringPool.h"
+
+#include <array>
+#include <androidfw/ResourceTypes.h>
+#include <ostream>
+#include <vector>
+
+namespace aapt {
+
+struct ValueVisitor;
+struct ConstValueVisitor;
+struct ValueVisitorArgs;
+
+/**
+ * A resource value. This is an all-encompassing representation
+ * of Item and Map and their subclasses. The way to do
+ * type specific operations is to check the Value's type() and
+ * cast it to the appropriate subclass. This isn't super clean,
+ * but it is the simplest strategy.
+ */
+struct Value {
+    /**
+     * Whether or not this is an Item.
+     */
+    virtual bool isItem() const;
+
+    /**
+     * Whether this value is weak and can be overriden without
+     * warning or error. Default for base class is false.
+     */
+    virtual bool isWeak() const;
+
+    /**
+     * Calls the appropriate overload of ValueVisitor.
+     */
+    virtual void accept(ValueVisitor& visitor, ValueVisitorArgs&& args) = 0;
+
+    /**
+     * Const version of accept().
+     */
+    virtual void accept(ConstValueVisitor& visitor, ValueVisitorArgs&& args) const = 0;
+
+    /**
+     * Clone the value.
+     */
+    virtual Value* clone() const = 0;
+
+    /**
+     * Human readable printout of this value.
+     */
+    virtual void print(std::ostream& out) const = 0;
+};
+
+/**
+ * Inherit from this to get visitor accepting implementations for free.
+ */
+template <typename Derived>
+struct BaseValue : public Value {
+    virtual void accept(ValueVisitor& visitor, ValueVisitorArgs&& args) override;
+    virtual void accept(ConstValueVisitor& visitor, ValueVisitorArgs&& args) const override;
+};
+
+/**
+ * A resource item with a single value. This maps to android::ResTable_entry.
+ */
+struct Item : public Value {
+    /**
+     * An Item is, of course, an Item.
+     */
+    virtual bool isItem() const override;
+
+    /**
+     * Clone the Item.
+     */
+    virtual Item* clone() const override = 0;
+
+    /**
+     * Fills in an android::Res_value structure with this Item's binary representation.
+     * Returns false if an error ocurred.
+     */
+    virtual bool flatten(android::Res_value& outValue) const = 0;
+};
+
+/**
+ * Inherit from this to get visitor accepting implementations for free.
+ */
+template <typename Derived>
+struct BaseItem : public Item {
+    virtual void accept(ValueVisitor& visitor, ValueVisitorArgs&& args) override;
+    virtual void accept(ConstValueVisitor& visitor, ValueVisitorArgs&& args) const override;
+};
+
+/**
+ * A reference to another resource. This maps to android::Res_value::TYPE_REFERENCE.
+ *
+ * A reference can be symbolic (with the name set to a valid resource name) or be
+ * numeric (the id is set to a valid resource ID).
+ */
+struct Reference : public BaseItem<Reference> {
+    enum class Type {
+        kResource,
+        kAttribute,
+    };
+
+    ResourceName name;
+    ResourceId id;
+    Reference::Type referenceType;
+    bool privateReference = false;
+
+    Reference();
+    Reference(const ResourceNameRef& n, Type type = Type::kResource);
+    Reference(const ResourceId& i, Type type = Type::kResource);
+
+    bool flatten(android::Res_value& outValue) const override;
+    Reference* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+/**
+ * An ID resource. Has no real value, just a place holder.
+ */
+struct Id : public BaseItem<Id> {
+    bool isWeak() const override;
+    bool flatten(android::Res_value& out) const override;
+    Id* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+/**
+ * A raw, unprocessed string. This may contain quotations,
+ * escape sequences, and whitespace. This shall *NOT*
+ * end up in the final resource table.
+ */
+struct RawString : public BaseItem<RawString> {
+    StringPool::Ref value;
+
+    RawString(const StringPool::Ref& ref);
+
+    bool flatten(android::Res_value& outValue) const override;
+    RawString* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+struct String : public BaseItem<String> {
+    StringPool::Ref value;
+
+    String(const StringPool::Ref& ref);
+
+    bool flatten(android::Res_value& outValue) const override;
+    String* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+struct StyledString : public BaseItem<StyledString> {
+    StringPool::StyleRef value;
+
+    StyledString(const StringPool::StyleRef& ref);
+
+    bool flatten(android::Res_value& outValue) const override;
+    StyledString* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+struct FileReference : public BaseItem<FileReference> {
+    StringPool::Ref path;
+
+    FileReference() = default;
+    FileReference(const StringPool::Ref& path);
+
+    bool flatten(android::Res_value& outValue) const override;
+    FileReference* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+/**
+ * Represents any other android::Res_value.
+ */
+struct BinaryPrimitive : public BaseItem<BinaryPrimitive> {
+    android::Res_value value;
+
+    BinaryPrimitive() = default;
+    BinaryPrimitive(const android::Res_value& val);
+
+    bool flatten(android::Res_value& outValue) const override;
+    BinaryPrimitive* clone() const override;
+    void print(::std::ostream& out) const override;
+};
+
+/**
+ * Sentinel value that should be ignored in the final output.
+ * Mainly used as a placeholder for public entries with no
+ * values defined yet.
+ */
+struct Sentinel : public BaseItem<Sentinel> {
+    bool isWeak() const override;
+    bool flatten(android::Res_value& outValue) const override;
+    Sentinel* clone() const override;
+    void print(::std::ostream& out) const override;
+};
+
+struct Attribute : public BaseValue<Attribute> {
+    struct Symbol {
+        Reference symbol;
+        uint32_t value;
+    };
+
+    bool weak;
+    uint32_t typeMask;
+    uint32_t minInt;
+    uint32_t maxInt;
+    std::vector<Symbol> symbols;
+
+    Attribute(bool w, uint32_t t = 0u);
+
+    bool isWeak() const override;
+    virtual Attribute* clone() const override;
+    virtual void print(std::ostream& out) const override;
+};
+
+struct Style : public BaseValue<Style> {
+    struct Entry {
+        Reference key;
+        std::unique_ptr<Item> value;
+    };
+
+    Reference parent;
+    std::vector<Entry> entries;
+
+    Style* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+struct Array : public BaseValue<Array> {
+    std::vector<std::unique_ptr<Item>> items;
+
+    Array* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+struct Plural : public BaseValue<Plural> {
+    enum {
+        Zero = 0,
+        One,
+        Two,
+        Few,
+        Many,
+        Other,
+        Count
+    };
+
+    std::array<std::unique_ptr<Item>, Count> values;
+
+    Plural* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+struct Styleable : public BaseValue<Styleable> {
+    std::vector<Reference> entries;
+
+    Styleable* clone() const override;
+    void print(std::ostream& out) const override;
+};
+
+/**
+ * Stream operator for printing Value objects.
+ */
+inline ::std::ostream& operator<<(::std::ostream& out, const Value& value) {
+    value.print(out);
+    return out;
+}
+
+/**
+ * The argument object that gets passed through the value
+ * back to the ValueVisitor. Subclasses of ValueVisitor should
+ * subclass ValueVisitorArgs to contain the data they need
+ * to operate.
+ */
+struct ValueVisitorArgs {};
+
+/**
+ * Visits a value and runs the appropriate method based on its type.
+ */
+struct ValueVisitor {
+    virtual void visit(Reference& reference, ValueVisitorArgs& args) {
+        visitItem(reference, args);
+    }
+
+    virtual void visit(RawString& string, ValueVisitorArgs& args) {
+        visitItem(string, args);
+    }
+
+    virtual void visit(String& string, ValueVisitorArgs& args) {
+        visitItem(string, args);
+    }
+
+    virtual void visit(StyledString& string, ValueVisitorArgs& args) {
+        visitItem(string, args);
+    }
+
+    virtual void visit(FileReference& file, ValueVisitorArgs& args) {
+        visitItem(file, args);
+    }
+
+    virtual void visit(Id& id, ValueVisitorArgs& args) {
+        visitItem(id, args);
+    }
+
+    virtual void visit(BinaryPrimitive& primitive, ValueVisitorArgs& args) {
+        visitItem(primitive, args);
+    }
+
+    virtual void visit(Sentinel& sentinel, ValueVisitorArgs& args) {
+        visitItem(sentinel, args);
+    }
+
+    virtual void visit(Attribute& attr, ValueVisitorArgs& args) {}
+    virtual void visit(Style& style, ValueVisitorArgs& args) {}
+    virtual void visit(Array& array, ValueVisitorArgs& args) {}
+    virtual void visit(Plural& array, ValueVisitorArgs& args) {}
+    virtual void visit(Styleable& styleable, ValueVisitorArgs& args) {}
+
+    virtual void visitItem(Item& item, ValueVisitorArgs& args) {}
+};
+
+/**
+ * Const version of ValueVisitor.
+ */
+struct ConstValueVisitor {
+    virtual void visit(const Reference& reference, ValueVisitorArgs& args) {
+        visitItem(reference, args);
+    }
+
+    virtual void visit(const RawString& string, ValueVisitorArgs& args) {
+        visitItem(string, args);
+    }
+
+    virtual void visit(const String& string, ValueVisitorArgs& args) {
+        visitItem(string, args);
+    }
+
+    virtual void visit(const StyledString& string, ValueVisitorArgs& args) {
+        visitItem(string, args);
+    }
+
+    virtual void visit(const FileReference& file, ValueVisitorArgs& args) {
+        visitItem(file, args);
+    }
+
+    virtual void visit(const Id& id, ValueVisitorArgs& args) {
+        visitItem(id, args);
+    }
+
+    virtual void visit(const BinaryPrimitive& primitive, ValueVisitorArgs& args) {
+        visitItem(primitive, args);
+    }
+
+    virtual void visit(const Sentinel& sentinel, ValueVisitorArgs& args) {
+        visitItem(sentinel, args);
+    }
+
+    virtual void visit(const Attribute& attr, ValueVisitorArgs& args) {}
+    virtual void visit(const Style& style, ValueVisitorArgs& args) {}
+    virtual void visit(const Array& array, ValueVisitorArgs& args) {}
+    virtual void visit(const Plural& array, ValueVisitorArgs& args) {}
+    virtual void visit(const Styleable& styleable, ValueVisitorArgs& args) {}
+
+    virtual void visitItem(const Item& item, ValueVisitorArgs& args) {}
+};
+
+/**
+ * Convenience Visitor that forwards a specific type to a function.
+ * Args are not used as the function can bind variables. Do not use
+ * directly, use the wrapper visitFunc() method.
+ */
+template <typename T, typename TFunc>
+struct ValueVisitorFunc : ValueVisitor {
+    TFunc func;
+
+    ValueVisitorFunc(TFunc f) : func(f) {
+    }
+
+    void visit(T& value, ValueVisitorArgs&) override {
+        func(value);
+    }
+};
+
+/**
+ * Const version of ValueVisitorFunc.
+ */
+template <typename T, typename TFunc>
+struct ConstValueVisitorFunc : ConstValueVisitor {
+    TFunc func;
+
+    ConstValueVisitorFunc(TFunc f) : func(f) {
+    }
+
+    void visit(const T& value, ValueVisitorArgs&) override {
+        func(value);
+    }
+};
+
+template <typename T, typename TFunc>
+void visitFunc(Value& value, TFunc f) {
+    ValueVisitorFunc<T, TFunc> visitor(f);
+    value.accept(visitor, ValueVisitorArgs{});
+}
+
+template <typename T, typename TFunc>
+void visitFunc(const Value& value, TFunc f) {
+    ConstValueVisitorFunc<T, TFunc> visitor(f);
+    value.accept(visitor, ValueVisitorArgs{});
+}
+
+template <typename Derived>
+void BaseValue<Derived>::accept(ValueVisitor& visitor, ValueVisitorArgs&& args) {
+    visitor.visit(static_cast<Derived&>(*this), args);
+}
+
+template <typename Derived>
+void BaseValue<Derived>::accept(ConstValueVisitor& visitor, ValueVisitorArgs&& args) const {
+    visitor.visit(static_cast<const Derived&>(*this), args);
+}
+
+template <typename Derived>
+void BaseItem<Derived>::accept(ValueVisitor& visitor, ValueVisitorArgs&& args) {
+    visitor.visit(static_cast<Derived&>(*this), args);
+}
+
+template <typename Derived>
+void BaseItem<Derived>::accept(ConstValueVisitor& visitor, ValueVisitorArgs&& args) const {
+    visitor.visit(static_cast<const Derived&>(*this), args);
+}
+
+} // namespace aapt
+
+#endif // AAPT_RESOURCE_VALUES_H
diff --git a/tools/aapt2/Resource_test.cpp b/tools/aapt2/Resource_test.cpp
new file mode 100644
index 0000000..d957999
--- /dev/null
+++ b/tools/aapt2/Resource_test.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "Resource.h"
+
+namespace aapt {
+
+TEST(ResourceTypeTest, ParseResourceTypes) {
+    const ResourceType* type = parseResourceType(u"anim");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kAnim);
+
+    type = parseResourceType(u"animator");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kAnimator);
+
+    type = parseResourceType(u"array");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kArray);
+
+    type = parseResourceType(u"attr");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kAttr);
+
+    type = parseResourceType(u"^attr-private");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kAttrPrivate);
+
+    type = parseResourceType(u"bool");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kBool);
+
+    type = parseResourceType(u"color");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kColor);
+
+    type = parseResourceType(u"dimen");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kDimen);
+
+    type = parseResourceType(u"drawable");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kDrawable);
+
+    type = parseResourceType(u"fraction");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kFraction);
+
+    type = parseResourceType(u"id");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kId);
+
+    type = parseResourceType(u"integer");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kInteger);
+
+    type = parseResourceType(u"integer-array");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kIntegerArray);
+
+    type = parseResourceType(u"interpolator");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kInterpolator);
+
+    type = parseResourceType(u"layout");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kLayout);
+
+    type = parseResourceType(u"menu");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kMenu);
+
+    type = parseResourceType(u"mipmap");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kMipmap);
+
+    type = parseResourceType(u"plurals");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kPlurals);
+
+    type = parseResourceType(u"raw");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kRaw);
+
+    type = parseResourceType(u"string");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kString);
+
+    type = parseResourceType(u"style");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kStyle);
+
+    type = parseResourceType(u"transition");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kTransition);
+
+    type = parseResourceType(u"xml");
+    ASSERT_NE(type, nullptr);
+    EXPECT_EQ(*type, ResourceType::kXml);
+
+    type = parseResourceType(u"blahaha");
+    EXPECT_EQ(type, nullptr);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ScopedXmlPullParser.cpp b/tools/aapt2/ScopedXmlPullParser.cpp
new file mode 100644
index 0000000..d9ae72c
--- /dev/null
+++ b/tools/aapt2/ScopedXmlPullParser.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ScopedXmlPullParser.h"
+
+#include <string>
+
+namespace aapt {
+
+ScopedXmlPullParser::ScopedXmlPullParser(XmlPullParser* parser) :
+        mParser(parser), mDepth(parser->getDepth()), mDone(false) {
+}
+
+ScopedXmlPullParser::~ScopedXmlPullParser() {
+    while (isGoodEvent(next()));
+}
+
+XmlPullParser::Event ScopedXmlPullParser::next() {
+    if (mDone) {
+        return Event::kEndDocument;
+    }
+
+    const Event event = mParser->next();
+    if (mParser->getDepth() <= mDepth) {
+        mDone = true;
+    }
+    return event;
+}
+
+XmlPullParser::Event ScopedXmlPullParser::getEvent() const {
+    return mParser->getEvent();
+}
+
+const std::string& ScopedXmlPullParser::getLastError() const {
+    return mParser->getLastError();
+}
+
+const std::u16string& ScopedXmlPullParser::getComment() const {
+    return mParser->getComment();
+}
+
+size_t ScopedXmlPullParser::getLineNumber() const {
+    return mParser->getLineNumber();
+}
+
+size_t ScopedXmlPullParser::getDepth() const {
+    const size_t depth = mParser->getDepth();
+    if (depth < mDepth) {
+        return 0;
+    }
+    return depth - mDepth;
+}
+
+const std::u16string& ScopedXmlPullParser::getText() const {
+    return mParser->getText();
+}
+
+const std::u16string& ScopedXmlPullParser::getNamespacePrefix() const {
+    return mParser->getNamespacePrefix();
+}
+
+const std::u16string& ScopedXmlPullParser::getNamespaceUri() const {
+    return mParser->getNamespaceUri();
+}
+
+const std::u16string& ScopedXmlPullParser::getElementNamespace() const {
+    return mParser->getElementNamespace();
+}
+
+const std::u16string& ScopedXmlPullParser::getElementName() const {
+    return mParser->getElementName();
+}
+
+size_t ScopedXmlPullParser::getAttributeCount() const {
+    return mParser->getAttributeCount();
+}
+
+XmlPullParser::const_iterator ScopedXmlPullParser::beginAttributes() const {
+    return mParser->beginAttributes();
+}
+
+XmlPullParser::const_iterator ScopedXmlPullParser::endAttributes() const {
+    return mParser->endAttributes();
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/ScopedXmlPullParser.h b/tools/aapt2/ScopedXmlPullParser.h
new file mode 100644
index 0000000..e660499
--- /dev/null
+++ b/tools/aapt2/ScopedXmlPullParser.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SCOPED_XML_PULL_PARSER_H
+#define AAPT_SCOPED_XML_PULL_PARSER_H
+
+#include "XmlPullParser.h"
+
+#include <string>
+
+namespace aapt {
+
+/**
+ * An XmlPullParser that will not read past the depth
+ * of the underlying parser. When this parser is destroyed,
+ * it moves the underlying parser to the same depth it
+ * started with.
+ *
+ * You can write code like this:
+ *
+ *   while (XmlPullParser::isGoodEvent(parser.next())) {
+ *     if (parser.getEvent() != XmlPullParser::Event::StartElement) {
+ *       continue;
+ *     }
+ *
+ *     ScopedXmlPullParser scoped(parser);
+ *     if (parser.getElementName() == u"id") {
+ *       // do work.
+ *     } else {
+ *       // do nothing, as all the sub elements will be skipped
+ *       // when scoped goes out of scope.
+ *     }
+ *   }
+ */
+class ScopedXmlPullParser : public XmlPullParser {
+public:
+    ScopedXmlPullParser(XmlPullParser* parser);
+    ScopedXmlPullParser(const ScopedXmlPullParser&) = delete;
+    ScopedXmlPullParser& operator=(const ScopedXmlPullParser&) = delete;
+    ~ScopedXmlPullParser();
+
+    Event getEvent() const;
+    const std::string& getLastError() const;
+    Event next();
+
+    const std::u16string& getComment() const;
+    size_t getLineNumber() const;
+    size_t getDepth() const;
+
+    const std::u16string& getText() const;
+
+    const std::u16string& getNamespacePrefix() const;
+    const std::u16string& getNamespaceUri() const;
+
+    const std::u16string& getElementNamespace() const;
+    const std::u16string& getElementName() const;
+
+    const_iterator beginAttributes() const;
+    const_iterator endAttributes() const;
+    size_t getAttributeCount() const;
+
+private:
+    XmlPullParser* mParser;
+    size_t mDepth;
+    bool mDone;
+};
+
+} // namespace aapt
+
+#endif // AAPT_SCOPED_XML_PULL_PARSER_H
diff --git a/tools/aapt2/ScopedXmlPullParser_test.cpp b/tools/aapt2/ScopedXmlPullParser_test.cpp
new file mode 100644
index 0000000..342f305
--- /dev/null
+++ b/tools/aapt2/ScopedXmlPullParser_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ScopedXmlPullParser.h"
+#include "SourceXmlPullParser.h"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+TEST(ScopedXmlPullParserTest, StopIteratingAtNoNZeroDepth) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl
+          << "<resources><string></string></resources>" << std::endl;
+
+    SourceXmlPullParser sourceParser(input);
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"resources"), sourceParser.getElementName());
+
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"string"), sourceParser.getElementName());
+
+    {
+        ScopedXmlPullParser scopedParser(&sourceParser);
+        EXPECT_EQ(XmlPullParser::Event::kEndElement, scopedParser.next());
+        EXPECT_EQ(std::u16string(u"string"), sourceParser.getElementName());
+
+        EXPECT_EQ(XmlPullParser::Event::kEndDocument, scopedParser.next());
+    }
+
+    EXPECT_EQ(XmlPullParser::Event::kEndElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"resources"), sourceParser.getElementName());
+
+    EXPECT_EQ(XmlPullParser::Event::kEndDocument, sourceParser.next());
+}
+
+TEST(ScopedXmlPullParserTest, FinishCurrentElementOnDestruction) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl
+          << "<resources><string></string></resources>" << std::endl;
+
+    SourceXmlPullParser sourceParser(input);
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"resources"), sourceParser.getElementName());
+
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"string"), sourceParser.getElementName());
+
+    {
+        ScopedXmlPullParser scopedParser(&sourceParser);
+        EXPECT_EQ(std::u16string(u"string"), sourceParser.getElementName());
+    }
+
+    EXPECT_EQ(XmlPullParser::Event::kEndElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"resources"), sourceParser.getElementName());
+
+    EXPECT_EQ(XmlPullParser::Event::kEndDocument, sourceParser.next());
+}
+
+TEST(ScopedXmlPullParserTest, NestedParsersOperateCorrectly) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl
+          << "<resources><string><foo></foo></string></resources>" << std::endl;
+
+    SourceXmlPullParser sourceParser(input);
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"resources"), sourceParser.getElementName());
+
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"string"), sourceParser.getElementName());
+
+    {
+        ScopedXmlPullParser scopedParser(&sourceParser);
+        EXPECT_EQ(std::u16string(u"string"), scopedParser.getElementName());
+        while (XmlPullParser::isGoodEvent(scopedParser.next())) {
+            if (scopedParser.getEvent() != XmlPullParser::Event::kStartElement) {
+                continue;
+            }
+
+            ScopedXmlPullParser subScopedParser(&scopedParser);
+            EXPECT_EQ(std::u16string(u"foo"), subScopedParser.getElementName());
+        }
+    }
+
+    EXPECT_EQ(XmlPullParser::Event::kEndElement, sourceParser.next());
+    EXPECT_EQ(std::u16string(u"resources"), sourceParser.getElementName());
+
+    EXPECT_EQ(XmlPullParser::Event::kEndDocument, sourceParser.next());
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
new file mode 100644
index 0000000..3f156a6
--- /dev/null
+++ b/tools/aapt2/SdkConstants.cpp
@@ -0,0 +1,693 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <unordered_map>
+
+namespace aapt {
+
+static const std::unordered_map<std::u16string, size_t> sAttrMap = {
+    { u"marqueeRepeatLimit", 2 },
+    { u"windowNoDisplay", 3 },
+    { u"backgroundDimEnabled", 3 },
+    { u"inputType", 3 },
+    { u"isDefault", 3 },
+    { u"windowDisablePreview", 3 },
+    { u"privateImeOptions", 3 },
+    { u"editorExtras", 3 },
+    { u"settingsActivity", 3 },
+    { u"fastScrollEnabled", 3 },
+    { u"reqTouchScreen", 3 },
+    { u"reqKeyboardType", 3 },
+    { u"reqHardKeyboard", 3 },
+    { u"reqNavigation", 3 },
+    { u"windowSoftInputMode", 3 },
+    { u"imeFullscreenBackground", 3 },
+    { u"noHistory", 3 },
+    { u"headerDividersEnabled", 3 },
+    { u"footerDividersEnabled", 3 },
+    { u"candidatesTextStyleSpans", 3 },
+    { u"smoothScrollbar", 3 },
+    { u"reqFiveWayNav", 3 },
+    { u"keyBackground", 3 },
+    { u"keyTextSize", 3 },
+    { u"labelTextSize", 3 },
+    { u"keyTextColor", 3 },
+    { u"keyPreviewLayout", 3 },
+    { u"keyPreviewOffset", 3 },
+    { u"keyPreviewHeight", 3 },
+    { u"verticalCorrection", 3 },
+    { u"popupLayout", 3 },
+    { u"state_long_pressable", 3 },
+    { u"keyWidth", 3 },
+    { u"keyHeight", 3 },
+    { u"horizontalGap", 3 },
+    { u"verticalGap", 3 },
+    { u"rowEdgeFlags", 3 },
+    { u"codes", 3 },
+    { u"popupKeyboard", 3 },
+    { u"popupCharacters", 3 },
+    { u"keyEdgeFlags", 3 },
+    { u"isModifier", 3 },
+    { u"isSticky", 3 },
+    { u"isRepeatable", 3 },
+    { u"iconPreview", 3 },
+    { u"keyOutputText", 3 },
+    { u"keyLabel", 3 },
+    { u"keyIcon", 3 },
+    { u"keyboardMode", 3 },
+    { u"isScrollContainer", 3 },
+    { u"fillEnabled", 3 },
+    { u"updatePeriodMillis", 3 },
+    { u"initialLayout", 3 },
+    { u"voiceSearchMode", 3 },
+    { u"voiceLanguageModel", 3 },
+    { u"voicePromptText", 3 },
+    { u"voiceLanguage", 3 },
+    { u"voiceMaxResults", 3 },
+    { u"bottomOffset", 3 },
+    { u"topOffset", 3 },
+    { u"allowSingleTap", 3 },
+    { u"handle", 3 },
+    { u"content", 3 },
+    { u"animateOnClick", 3 },
+    { u"configure", 3 },
+    { u"hapticFeedbackEnabled", 3 },
+    { u"innerRadius", 3 },
+    { u"thickness", 3 },
+    { u"sharedUserLabel", 3 },
+    { u"dropDownWidth", 3 },
+    { u"dropDownAnchor", 3 },
+    { u"imeOptions", 3 },
+    { u"imeActionLabel", 3 },
+    { u"imeActionId", 3 },
+    { u"imeExtractEnterAnimation", 3 },
+    { u"imeExtractExitAnimation", 3 },
+    { u"tension", 4 },
+    { u"extraTension", 4 },
+    { u"anyDensity", 4 },
+    { u"searchSuggestThreshold", 4 },
+    { u"includeInGlobalSearch", 4 },
+    { u"onClick", 4 },
+    { u"targetSdkVersion", 4 },
+    { u"maxSdkVersion", 4 },
+    { u"testOnly", 4 },
+    { u"contentDescription", 4 },
+    { u"gestureStrokeWidth", 4 },
+    { u"gestureColor", 4 },
+    { u"uncertainGestureColor", 4 },
+    { u"fadeOffset", 4 },
+    { u"fadeDuration", 4 },
+    { u"gestureStrokeType", 4 },
+    { u"gestureStrokeLengthThreshold", 4 },
+    { u"gestureStrokeSquarenessThreshold", 4 },
+    { u"gestureStrokeAngleThreshold", 4 },
+    { u"eventsInterceptionEnabled", 4 },
+    { u"fadeEnabled", 4 },
+    { u"backupAgent", 4 },
+    { u"allowBackup", 4 },
+    { u"glEsVersion", 4 },
+    { u"queryAfterZeroResults", 4 },
+    { u"dropDownHeight", 4 },
+    { u"smallScreens", 4 },
+    { u"normalScreens", 4 },
+    { u"largeScreens", 4 },
+    { u"progressBarStyleInverse", 4 },
+    { u"progressBarStyleSmallInverse", 4 },
+    { u"progressBarStyleLargeInverse", 4 },
+    { u"searchSettingsDescription", 4 },
+    { u"textColorPrimaryInverseDisableOnly", 4 },
+    { u"autoUrlDetect", 4 },
+    { u"resizeable", 4 },
+    { u"required", 5 },
+    { u"accountType", 5 },
+    { u"contentAuthority", 5 },
+    { u"userVisible", 5 },
+    { u"windowShowWallpaper", 5 },
+    { u"wallpaperOpenEnterAnimation", 5 },
+    { u"wallpaperOpenExitAnimation", 5 },
+    { u"wallpaperCloseEnterAnimation", 5 },
+    { u"wallpaperCloseExitAnimation", 5 },
+    { u"wallpaperIntraOpenEnterAnimation", 5 },
+    { u"wallpaperIntraOpenExitAnimation", 5 },
+    { u"wallpaperIntraCloseEnterAnimation", 5 },
+    { u"wallpaperIntraCloseExitAnimation", 5 },
+    { u"supportsUploading", 5 },
+    { u"killAfterRestore", 5 },
+    { u"restoreNeedsApplication", 5 },
+    { u"smallIcon", 5 },
+    { u"accountPreferences", 5 },
+    { u"textAppearanceSearchResultSubtitle", 5 },
+    { u"textAppearanceSearchResultTitle", 5 },
+    { u"summaryColumn", 5 },
+    { u"detailColumn", 5 },
+    { u"detailSocialSummary", 5 },
+    { u"thumbnail", 5 },
+    { u"detachWallpaper", 5 },
+    { u"finishOnCloseSystemDialogs", 5 },
+    { u"scrollbarFadeDuration", 5 },
+    { u"scrollbarDefaultDelayBeforeFade", 5 },
+    { u"fadeScrollbars", 5 },
+    { u"colorBackgroundCacheHint", 5 },
+    { u"dropDownHorizontalOffset", 5 },
+    { u"dropDownVerticalOffset", 5 },
+    { u"quickContactBadgeStyleWindowSmall", 6 },
+    { u"quickContactBadgeStyleWindowMedium", 6 },
+    { u"quickContactBadgeStyleWindowLarge", 6 },
+    { u"quickContactBadgeStyleSmallWindowSmall", 6 },
+    { u"quickContactBadgeStyleSmallWindowMedium", 6 },
+    { u"quickContactBadgeStyleSmallWindowLarge", 6 },
+    { u"author", 7 },
+    { u"autoStart", 7 },
+    { u"expandableListViewWhiteStyle", 8 },
+    { u"installLocation", 8 },
+    { u"vmSafeMode", 8 },
+    { u"webTextViewStyle", 8 },
+    { u"restoreAnyVersion", 8 },
+    { u"tabStripLeft", 8 },
+    { u"tabStripRight", 8 },
+    { u"tabStripEnabled", 8 },
+    { u"logo", 9 },
+    { u"xlargeScreens", 9 },
+    { u"immersive", 9 },
+    { u"overScrollMode", 9 },
+    { u"overScrollHeader", 9 },
+    { u"overScrollFooter", 9 },
+    { u"filterTouchesWhenObscured", 9 },
+    { u"textSelectHandleLeft", 9 },
+    { u"textSelectHandleRight", 9 },
+    { u"textSelectHandle", 9 },
+    { u"textSelectHandleWindowStyle", 9 },
+    { u"popupAnimationStyle", 9 },
+    { u"screenSize", 9 },
+    { u"screenDensity", 9 },
+    { u"allContactsName", 11 },
+    { u"windowActionBar", 11 },
+    { u"actionBarStyle", 11 },
+    { u"navigationMode", 11 },
+    { u"displayOptions", 11 },
+    { u"subtitle", 11 },
+    { u"customNavigationLayout", 11 },
+    { u"hardwareAccelerated", 11 },
+    { u"measureWithLargestChild", 11 },
+    { u"animateFirstView", 11 },
+    { u"dropDownSpinnerStyle", 11 },
+    { u"actionDropDownStyle", 11 },
+    { u"actionButtonStyle", 11 },
+    { u"showAsAction", 11 },
+    { u"previewImage", 11 },
+    { u"actionModeBackground", 11 },
+    { u"actionModeCloseDrawable", 11 },
+    { u"windowActionModeOverlay", 11 },
+    { u"valueFrom", 11 },
+    { u"valueTo", 11 },
+    { u"valueType", 11 },
+    { u"propertyName", 11 },
+    { u"ordering", 11 },
+    { u"fragment", 11 },
+    { u"windowActionBarOverlay", 11 },
+    { u"fragmentOpenEnterAnimation", 11 },
+    { u"fragmentOpenExitAnimation", 11 },
+    { u"fragmentCloseEnterAnimation", 11 },
+    { u"fragmentCloseExitAnimation", 11 },
+    { u"fragmentFadeEnterAnimation", 11 },
+    { u"fragmentFadeExitAnimation", 11 },
+    { u"actionBarSize", 11 },
+    { u"imeSubtypeLocale", 11 },
+    { u"imeSubtypeMode", 11 },
+    { u"imeSubtypeExtraValue", 11 },
+    { u"splitMotionEvents", 11 },
+    { u"listChoiceBackgroundIndicator", 11 },
+    { u"spinnerMode", 11 },
+    { u"animateLayoutChanges", 11 },
+    { u"actionBarTabStyle", 11 },
+    { u"actionBarTabBarStyle", 11 },
+    { u"actionBarTabTextStyle", 11 },
+    { u"actionOverflowButtonStyle", 11 },
+    { u"actionModeCloseButtonStyle", 11 },
+    { u"titleTextStyle", 11 },
+    { u"subtitleTextStyle", 11 },
+    { u"iconifiedByDefault", 11 },
+    { u"actionLayout", 11 },
+    { u"actionViewClass", 11 },
+    { u"activatedBackgroundIndicator", 11 },
+    { u"state_activated", 11 },
+    { u"listPopupWindowStyle", 11 },
+    { u"popupMenuStyle", 11 },
+    { u"textAppearanceLargePopupMenu", 11 },
+    { u"textAppearanceSmallPopupMenu", 11 },
+    { u"breadCrumbTitle", 11 },
+    { u"breadCrumbShortTitle", 11 },
+    { u"listDividerAlertDialog", 11 },
+    { u"textColorAlertDialogListItem", 11 },
+    { u"loopViews", 11 },
+    { u"dialogTheme", 11 },
+    { u"alertDialogTheme", 11 },
+    { u"dividerVertical", 11 },
+    { u"homeAsUpIndicator", 11 },
+    { u"enterFadeDuration", 11 },
+    { u"exitFadeDuration", 11 },
+    { u"selectableItemBackground", 11 },
+    { u"autoAdvanceViewId", 11 },
+    { u"useIntrinsicSizeAsMinimum", 11 },
+    { u"actionModeCutDrawable", 11 },
+    { u"actionModeCopyDrawable", 11 },
+    { u"actionModePasteDrawable", 11 },
+    { u"textEditPasteWindowLayout", 11 },
+    { u"textEditNoPasteWindowLayout", 11 },
+    { u"textIsSelectable", 11 },
+    { u"windowEnableSplitTouch", 11 },
+    { u"indeterminateProgressStyle", 11 },
+    { u"progressBarPadding", 11 },
+    { u"animationResolution", 11 },
+    { u"state_accelerated", 11 },
+    { u"baseline", 11 },
+    { u"homeLayout", 11 },
+    { u"opacity", 11 },
+    { u"alpha", 11 },
+    { u"transformPivotX", 11 },
+    { u"transformPivotY", 11 },
+    { u"translationX", 11 },
+    { u"translationY", 11 },
+    { u"scaleX", 11 },
+    { u"scaleY", 11 },
+    { u"rotation", 11 },
+    { u"rotationX", 11 },
+    { u"rotationY", 11 },
+    { u"showDividers", 11 },
+    { u"dividerPadding", 11 },
+    { u"borderlessButtonStyle", 11 },
+    { u"dividerHorizontal", 11 },
+    { u"itemPadding", 11 },
+    { u"buttonBarStyle", 11 },
+    { u"buttonBarButtonStyle", 11 },
+    { u"segmentedButtonStyle", 11 },
+    { u"staticWallpaperPreview", 11 },
+    { u"allowParallelSyncs", 11 },
+    { u"isAlwaysSyncable", 11 },
+    { u"verticalScrollbarPosition", 11 },
+    { u"fastScrollAlwaysVisible", 11 },
+    { u"fastScrollThumbDrawable", 11 },
+    { u"fastScrollPreviewBackgroundLeft", 11 },
+    { u"fastScrollPreviewBackgroundRight", 11 },
+    { u"fastScrollTrackDrawable", 11 },
+    { u"fastScrollOverlayPosition", 11 },
+    { u"customTokens", 11 },
+    { u"nextFocusForward", 11 },
+    { u"firstDayOfWeek", 11 },
+    { u"showWeekNumber", 11 },
+    { u"minDate", 11 },
+    { u"maxDate", 11 },
+    { u"shownWeekCount", 11 },
+    { u"selectedWeekBackgroundColor", 11 },
+    { u"focusedMonthDateColor", 11 },
+    { u"unfocusedMonthDateColor", 11 },
+    { u"weekNumberColor", 11 },
+    { u"weekSeparatorLineColor", 11 },
+    { u"selectedDateVerticalBar", 11 },
+    { u"weekDayTextAppearance", 11 },
+    { u"dateTextAppearance", 11 },
+    { u"solidColor", 11 },
+    { u"spinnersShown", 11 },
+    { u"calendarViewShown", 11 },
+    { u"state_multiline", 11 },
+    { u"detailsElementBackground", 11 },
+    { u"textColorHighlightInverse", 11 },
+    { u"textColorLinkInverse", 11 },
+    { u"editTextColor", 11 },
+    { u"editTextBackground", 11 },
+    { u"horizontalScrollViewStyle", 11 },
+    { u"layerType", 11 },
+    { u"alertDialogIcon", 11 },
+    { u"windowMinWidthMajor", 11 },
+    { u"windowMinWidthMinor", 11 },
+    { u"queryHint", 11 },
+    { u"fastScrollTextColor", 11 },
+    { u"largeHeap", 11 },
+    { u"windowCloseOnTouchOutside", 11 },
+    { u"datePickerStyle", 11 },
+    { u"calendarViewStyle", 11 },
+    { u"textEditSidePasteWindowLayout", 11 },
+    { u"textEditSideNoPasteWindowLayout", 11 },
+    { u"actionMenuTextAppearance", 11 },
+    { u"actionMenuTextColor", 11 },
+    { u"textCursorDrawable", 12 },
+    { u"resizeMode", 12 },
+    { u"requiresSmallestWidthDp", 12 },
+    { u"compatibleWidthLimitDp", 12 },
+    { u"largestWidthLimitDp", 12 },
+    { u"state_hovered", 13 },
+    { u"state_drag_can_accept", 13 },
+    { u"state_drag_hovered", 13 },
+    { u"stopWithTask", 13 },
+    { u"switchTextOn", 13 },
+    { u"switchTextOff", 13 },
+    { u"switchPreferenceStyle", 13 },
+    { u"switchTextAppearance", 13 },
+    { u"track", 13 },
+    { u"switchMinWidth", 13 },
+    { u"switchPadding", 13 },
+    { u"thumbTextPadding", 13 },
+    { u"textSuggestionsWindowStyle", 13 },
+    { u"textEditSuggestionItemLayout", 13 },
+    { u"rowCount", 13 },
+    { u"rowOrderPreserved", 13 },
+    { u"columnCount", 13 },
+    { u"columnOrderPreserved", 13 },
+    { u"useDefaultMargins", 13 },
+    { u"alignmentMode", 13 },
+    { u"layout_row", 13 },
+    { u"layout_rowSpan", 13 },
+    { u"layout_columnSpan", 13 },
+    { u"actionModeSelectAllDrawable", 13 },
+    { u"isAuxiliary", 13 },
+    { u"accessibilityEventTypes", 13 },
+    { u"packageNames", 13 },
+    { u"accessibilityFeedbackType", 13 },
+    { u"notificationTimeout", 13 },
+    { u"accessibilityFlags", 13 },
+    { u"canRetrieveWindowContent", 13 },
+    { u"listPreferredItemHeightLarge", 13 },
+    { u"listPreferredItemHeightSmall", 13 },
+    { u"actionBarSplitStyle", 13 },
+    { u"actionProviderClass", 13 },
+    { u"backgroundStacked", 13 },
+    { u"backgroundSplit", 13 },
+    { u"textAllCaps", 13 },
+    { u"colorPressedHighlight", 13 },
+    { u"colorLongPressedHighlight", 13 },
+    { u"colorFocusedHighlight", 13 },
+    { u"colorActivatedHighlight", 13 },
+    { u"colorMultiSelectHighlight", 13 },
+    { u"drawableStart", 13 },
+    { u"drawableEnd", 13 },
+    { u"actionModeStyle", 13 },
+    { u"minResizeWidth", 13 },
+    { u"minResizeHeight", 13 },
+    { u"actionBarWidgetTheme", 13 },
+    { u"uiOptions", 13 },
+    { u"subtypeLocale", 13 },
+    { u"subtypeExtraValue", 13 },
+    { u"actionBarDivider", 13 },
+    { u"actionBarItemBackground", 13 },
+    { u"actionModeSplitBackground", 13 },
+    { u"textAppearanceListItem", 13 },
+    { u"textAppearanceListItemSmall", 13 },
+    { u"targetDescriptions", 13 },
+    { u"directionDescriptions", 13 },
+    { u"overridesImplicitlyEnabledSubtype", 13 },
+    { u"listPreferredItemPaddingLeft", 13 },
+    { u"listPreferredItemPaddingRight", 13 },
+    { u"requiresFadingEdge", 13 },
+    { u"publicKey", 13 },
+    { u"parentActivityName", 16 },
+    { u"isolatedProcess", 16 },
+    { u"importantForAccessibility", 16 },
+    { u"keyboardLayout", 16 },
+    { u"fontFamily", 16 },
+    { u"mediaRouteButtonStyle", 16 },
+    { u"mediaRouteTypes", 16 },
+    { u"supportsRtl", 17 },
+    { u"textDirection", 17 },
+    { u"textAlignment", 17 },
+    { u"layoutDirection", 17 },
+    { u"paddingStart", 17 },
+    { u"paddingEnd", 17 },
+    { u"layout_marginStart", 17 },
+    { u"layout_marginEnd", 17 },
+    { u"layout_toStartOf", 17 },
+    { u"layout_toEndOf", 17 },
+    { u"layout_alignStart", 17 },
+    { u"layout_alignEnd", 17 },
+    { u"layout_alignParentStart", 17 },
+    { u"layout_alignParentEnd", 17 },
+    { u"listPreferredItemPaddingStart", 17 },
+    { u"listPreferredItemPaddingEnd", 17 },
+    { u"singleUser", 17 },
+    { u"presentationTheme", 17 },
+    { u"subtypeId", 17 },
+    { u"initialKeyguardLayout", 17 },
+    { u"widgetCategory", 17 },
+    { u"permissionGroupFlags", 17 },
+    { u"labelFor", 17 },
+    { u"permissionFlags", 17 },
+    { u"checkedTextViewStyle", 17 },
+    { u"showOnLockScreen", 17 },
+    { u"format12Hour", 17 },
+    { u"format24Hour", 17 },
+    { u"timeZone", 17 },
+    { u"mipMap", 18 },
+    { u"mirrorForRtl", 18 },
+    { u"windowOverscan", 18 },
+    { u"requiredForAllUsers", 18 },
+    { u"indicatorStart", 18 },
+    { u"indicatorEnd", 18 },
+    { u"childIndicatorStart", 18 },
+    { u"childIndicatorEnd", 18 },
+    { u"restrictedAccountType", 18 },
+    { u"requiredAccountType", 18 },
+    { u"canRequestTouchExplorationMode", 18 },
+    { u"canRequestEnhancedWebAccessibility", 18 },
+    { u"canRequestFilterKeyEvents", 18 },
+    { u"layoutMode", 18 },
+    { u"keySet", 19 },
+    { u"targetId", 19 },
+    { u"fromScene", 19 },
+    { u"toScene", 19 },
+    { u"transition", 19 },
+    { u"transitionOrdering", 19 },
+    { u"fadingMode", 19 },
+    { u"startDelay", 19 },
+    { u"ssp", 19 },
+    { u"sspPrefix", 19 },
+    { u"sspPattern", 19 },
+    { u"addPrintersActivity", 19 },
+    { u"vendor", 19 },
+    { u"category", 19 },
+    { u"isAsciiCapable", 19 },
+    { u"autoMirrored", 19 },
+    { u"supportsSwitchingToNextInputMethod", 19 },
+    { u"requireDeviceUnlock", 19 },
+    { u"apduServiceBanner", 19 },
+    { u"accessibilityLiveRegion", 19 },
+    { u"windowTranslucentStatus", 19 },
+    { u"windowTranslucentNavigation", 19 },
+    { u"advancedPrintOptionsActivity", 19 },
+    { u"banner", 20 },
+    { u"windowSwipeToDismiss", 20 },
+    { u"isGame", 20 },
+    { u"allowEmbedded", 20 },
+    { u"setupActivity", 20 },
+    { u"fastScrollStyle", 21 },
+    { u"windowContentTransitions", 21 },
+    { u"windowContentTransitionManager", 21 },
+    { u"translationZ", 21 },
+    { u"tintMode", 21 },
+    { u"controlX1", 21 },
+    { u"controlY1", 21 },
+    { u"controlX2", 21 },
+    { u"controlY2", 21 },
+    { u"transitionName", 21 },
+    { u"transitionGroup", 21 },
+    { u"viewportWidth", 21 },
+    { u"viewportHeight", 21 },
+    { u"fillColor", 21 },
+    { u"pathData", 21 },
+    { u"strokeColor", 21 },
+    { u"strokeWidth", 21 },
+    { u"trimPathStart", 21 },
+    { u"trimPathEnd", 21 },
+    { u"trimPathOffset", 21 },
+    { u"strokeLineCap", 21 },
+    { u"strokeLineJoin", 21 },
+    { u"strokeMiterLimit", 21 },
+    { u"colorControlNormal", 21 },
+    { u"colorControlActivated", 21 },
+    { u"colorButtonNormal", 21 },
+    { u"colorControlHighlight", 21 },
+    { u"persistableMode", 21 },
+    { u"titleTextAppearance", 21 },
+    { u"subtitleTextAppearance", 21 },
+    { u"slideEdge", 21 },
+    { u"actionBarTheme", 21 },
+    { u"textAppearanceListItemSecondary", 21 },
+    { u"colorPrimary", 21 },
+    { u"colorPrimaryDark", 21 },
+    { u"colorAccent", 21 },
+    { u"nestedScrollingEnabled", 21 },
+    { u"windowEnterTransition", 21 },
+    { u"windowExitTransition", 21 },
+    { u"windowSharedElementEnterTransition", 21 },
+    { u"windowSharedElementExitTransition", 21 },
+    { u"windowAllowReturnTransitionOverlap", 21 },
+    { u"windowAllowEnterTransitionOverlap", 21 },
+    { u"sessionService", 21 },
+    { u"stackViewStyle", 21 },
+    { u"switchStyle", 21 },
+    { u"elevation", 21 },
+    { u"excludeId", 21 },
+    { u"excludeClass", 21 },
+    { u"hideOnContentScroll", 21 },
+    { u"actionOverflowMenuStyle", 21 },
+    { u"documentLaunchMode", 21 },
+    { u"maxRecents", 21 },
+    { u"autoRemoveFromRecents", 21 },
+    { u"stateListAnimator", 21 },
+    { u"toId", 21 },
+    { u"fromId", 21 },
+    { u"reversible", 21 },
+    { u"splitTrack", 21 },
+    { u"targetName", 21 },
+    { u"excludeName", 21 },
+    { u"matchOrder", 21 },
+    { u"windowDrawsSystemBarBackgrounds", 21 },
+    { u"statusBarColor", 21 },
+    { u"navigationBarColor", 21 },
+    { u"contentInsetStart", 21 },
+    { u"contentInsetEnd", 21 },
+    { u"contentInsetLeft", 21 },
+    { u"contentInsetRight", 21 },
+    { u"paddingMode", 21 },
+    { u"layout_rowWeight", 21 },
+    { u"layout_columnWeight", 21 },
+    { u"translateX", 21 },
+    { u"translateY", 21 },
+    { u"selectableItemBackgroundBorderless", 21 },
+    { u"elegantTextHeight", 21 },
+    { u"searchKeyphraseId", 21 },
+    { u"searchKeyphrase", 21 },
+    { u"searchKeyphraseSupportedLocales", 21 },
+    { u"windowTransitionBackgroundFadeDuration", 21 },
+    { u"overlapAnchor", 21 },
+    { u"progressTint", 21 },
+    { u"progressTintMode", 21 },
+    { u"progressBackgroundTint", 21 },
+    { u"progressBackgroundTintMode", 21 },
+    { u"secondaryProgressTint", 21 },
+    { u"secondaryProgressTintMode", 21 },
+    { u"indeterminateTint", 21 },
+    { u"indeterminateTintMode", 21 },
+    { u"backgroundTint", 21 },
+    { u"backgroundTintMode", 21 },
+    { u"foregroundTint", 21 },
+    { u"foregroundTintMode", 21 },
+    { u"buttonTint", 21 },
+    { u"buttonTintMode", 21 },
+    { u"thumbTint", 21 },
+    { u"thumbTintMode", 21 },
+    { u"fullBackupOnly", 21 },
+    { u"propertyXName", 21 },
+    { u"propertyYName", 21 },
+    { u"relinquishTaskIdentity", 21 },
+    { u"tileModeX", 21 },
+    { u"tileModeY", 21 },
+    { u"actionModeShareDrawable", 21 },
+    { u"actionModeFindDrawable", 21 },
+    { u"actionModeWebSearchDrawable", 21 },
+    { u"transitionVisibilityMode", 21 },
+    { u"minimumHorizontalAngle", 21 },
+    { u"minimumVerticalAngle", 21 },
+    { u"maximumAngle", 21 },
+    { u"searchViewStyle", 21 },
+    { u"closeIcon", 21 },
+    { u"goIcon", 21 },
+    { u"searchIcon", 21 },
+    { u"voiceIcon", 21 },
+    { u"commitIcon", 21 },
+    { u"suggestionRowLayout", 21 },
+    { u"queryBackground", 21 },
+    { u"submitBackground", 21 },
+    { u"buttonBarPositiveButtonStyle", 21 },
+    { u"buttonBarNeutralButtonStyle", 21 },
+    { u"buttonBarNegativeButtonStyle", 21 },
+    { u"popupElevation", 21 },
+    { u"actionBarPopupTheme", 21 },
+    { u"multiArch", 21 },
+    { u"touchscreenBlocksFocus", 21 },
+    { u"windowElevation", 21 },
+    { u"launchTaskBehindTargetAnimation", 21 },
+    { u"launchTaskBehindSourceAnimation", 21 },
+    { u"restrictionType", 21 },
+    { u"dayOfWeekBackground", 21 },
+    { u"dayOfWeekTextAppearance", 21 },
+    { u"headerMonthTextAppearance", 21 },
+    { u"headerDayOfMonthTextAppearance", 21 },
+    { u"headerYearTextAppearance", 21 },
+    { u"yearListItemTextAppearance", 21 },
+    { u"yearListSelectorColor", 21 },
+    { u"calendarTextColor", 21 },
+    { u"recognitionService", 21 },
+    { u"timePickerStyle", 21 },
+    { u"timePickerDialogTheme", 21 },
+    { u"headerTimeTextAppearance", 21 },
+    { u"headerAmPmTextAppearance", 21 },
+    { u"numbersTextColor", 21 },
+    { u"numbersBackgroundColor", 21 },
+    { u"numbersSelectorColor", 21 },
+    { u"amPmTextColor", 21 },
+    { u"amPmBackgroundColor", 21 },
+    { u"searchKeyphraseRecognitionFlags", 21 },
+    { u"checkMarkTint", 21 },
+    { u"checkMarkTintMode", 21 },
+    { u"popupTheme", 21 },
+    { u"toolbarStyle", 21 },
+    { u"windowClipToOutline", 21 },
+    { u"datePickerDialogTheme", 21 },
+    { u"showText", 21 },
+    { u"windowReturnTransition", 21 },
+    { u"windowReenterTransition", 21 },
+    { u"windowSharedElementReturnTransition", 21 },
+    { u"windowSharedElementReenterTransition", 21 },
+    { u"resumeWhilePausing", 21 },
+    { u"datePickerMode", 21 },
+    { u"timePickerMode", 21 },
+    { u"inset", 21 },
+    { u"letterSpacing", 21 },
+    { u"fontFeatureSettings", 21 },
+    { u"outlineProvider", 21 },
+    { u"contentAgeHint", 21 },
+    { u"country", 21 },
+    { u"windowSharedElementsUseOverlay", 21 },
+    { u"reparent", 21 },
+    { u"reparentWithOverlay", 21 },
+    { u"ambientShadowAlpha", 21 },
+    { u"spotShadowAlpha", 21 },
+    { u"navigationIcon", 21 },
+    { u"navigationContentDescription", 21 },
+    { u"fragmentExitTransition", 21 },
+    { u"fragmentEnterTransition", 21 },
+    { u"fragmentSharedElementEnterTransition", 21 },
+    { u"fragmentReturnTransition", 21 },
+    { u"fragmentSharedElementReturnTransition", 21 },
+    { u"fragmentReenterTransition", 21 },
+    { u"fragmentAllowEnterTransitionOverlap", 21 },
+    { u"fragmentAllowReturnTransitionOverlap", 21 },
+    { u"patternPathData", 21 },
+    { u"strokeAlpha", 21 },
+    { u"fillAlpha", 21 },
+    { u"windowActivityTransitions", 21 },
+    { u"colorEdgeEffect", 21 }
+};
+
+size_t findAttributeSdkLevel(const std::u16string& name) {
+    auto iter = sAttrMap.find(name);
+    if (iter != sAttrMap.end()) {
+        return iter->second;
+    }
+    return 0;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
new file mode 100644
index 0000000..469c355
--- /dev/null
+++ b/tools/aapt2/SdkConstants.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SDK_CONSTANTS_H
+#define AAPT_SDK_CONSTANTS_H
+
+#include "Resource.h"
+
+#include <string>
+
+namespace aapt {
+
+enum {
+    SDK_CUPCAKE = 3,
+    SDK_DONUT = 4,
+    SDK_ECLAIR = 5,
+    SDK_ECLAIR_0_1 = 6,
+    SDK_ECLAIR_MR1 = 7,
+    SDK_FROYO = 8,
+    SDK_GINGERBREAD = 9,
+    SDK_GINGERBREAD_MR1 = 10,
+    SDK_HONEYCOMB = 11,
+    SDK_HONEYCOMB_MR1 = 12,
+    SDK_HONEYCOMB_MR2 = 13,
+    SDK_ICE_CREAM_SANDWICH = 14,
+    SDK_ICE_CREAM_SANDWICH_MR1 = 15,
+    SDK_JELLY_BEAN = 16,
+    SDK_JELLY_BEAN_MR1 = 17,
+    SDK_JELLY_BEAN_MR2 = 18,
+    SDK_KITKAT = 19,
+    SDK_KITKAT_WATCH = 20,
+    SDK_LOLLIPOP = 21,
+    SDK_LOLLIPOP_MR1 = 22,
+};
+
+size_t findAttributeSdkLevel(const std::u16string& name);
+
+} // namespace aapt
+
+#endif // AAPT_SDK_CONSTANTS_H
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
new file mode 100644
index 0000000..10c75aa
--- /dev/null
+++ b/tools/aapt2/Source.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SOURCE_H
+#define AAPT_SOURCE_H
+
+#include <ostream>
+#include <string>
+
+namespace aapt {
+
+struct SourceLineColumn;
+struct SourceLine;
+
+/**
+ * Represents a file on disk. Used for logging and
+ * showing errors.
+ */
+struct Source {
+    std::string path;
+
+    inline SourceLine line(size_t line) const;
+};
+
+/**
+ * Represents a file on disk and a line number in that file.
+ * Used for logging and showing errors.
+ */
+struct SourceLine {
+    std::string path;
+    size_t line;
+
+    inline SourceLineColumn column(size_t column) const;
+};
+
+/**
+ * Represents a file on disk and a line:column number in that file.
+ * Used for logging and showing errors.
+ */
+struct SourceLineColumn {
+    std::string path;
+    size_t line;
+    size_t column;
+};
+
+//
+// Implementations
+//
+
+SourceLine Source::line(size_t line) const {
+    return SourceLine{ path, line };
+}
+
+SourceLineColumn SourceLine::column(size_t column) const {
+    return SourceLineColumn{ path, line, column };
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const Source& source) {
+    return out << source.path;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const SourceLine& source) {
+    return out << source.path << ":" << source.line;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const SourceLineColumn& source) {
+    return out << source.path << ":" << source.line << ":" << source.column;
+}
+
+} // namespace aapt
+
+#endif // AAPT_SOURCE_H
diff --git a/tools/aapt2/SourceXmlPullParser.cpp b/tools/aapt2/SourceXmlPullParser.cpp
new file mode 100644
index 0000000..cb6a3c0
--- /dev/null
+++ b/tools/aapt2/SourceXmlPullParser.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "SourceXmlPullParser.h"
+#include "Util.h"
+
+namespace aapt {
+
+constexpr char kXmlNamespaceSep = 1;
+
+SourceXmlPullParser::SourceXmlPullParser(std::istream& in) : mIn(in), mEmpty(), mDepth(0) {
+    mParser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
+    XML_SetUserData(mParser, this);
+    XML_SetElementHandler(mParser, startElementHandler, endElementHandler);
+    XML_SetNamespaceDeclHandler(mParser, startNamespaceHandler, endNamespaceHandler);
+    XML_SetCharacterDataHandler(mParser, characterDataHandler);
+    XML_SetCommentHandler(mParser, commentDataHandler);
+    mEventQueue.push(EventData{ Event::kStartDocument, 0, mDepth++ });
+}
+
+SourceXmlPullParser::~SourceXmlPullParser() {
+    XML_ParserFree(mParser);
+}
+
+SourceXmlPullParser::Event SourceXmlPullParser::next() {
+    const Event currentEvent = getEvent();
+    if (currentEvent == Event::kBadDocument || currentEvent == Event::kEndDocument) {
+        return currentEvent;
+    }
+
+    mEventQueue.pop();
+    while (mEventQueue.empty()) {
+        mIn.read(mBuffer, sizeof(mBuffer) / sizeof(*mBuffer));
+
+        const bool done = mIn.eof();
+        if (mIn.bad() && !done) {
+            mLastError = strerror(errno);
+            mEventQueue.push(EventData{ Event::kBadDocument });
+            continue;
+        }
+
+        if (XML_Parse(mParser, mBuffer, mIn.gcount(), done) == XML_STATUS_ERROR) {
+            mLastError = XML_ErrorString(XML_GetErrorCode(mParser));
+            mEventQueue.push(EventData{ Event::kBadDocument });
+            continue;
+        }
+
+        if (done) {
+            mEventQueue.push(EventData{ Event::kEndDocument, 0, 0 });
+        }
+    }
+
+    return getEvent();
+}
+
+SourceXmlPullParser::Event SourceXmlPullParser::getEvent() const {
+    return mEventQueue.front().event;
+}
+
+const std::string& SourceXmlPullParser::getLastError() const {
+    return mLastError;
+}
+
+const std::u16string& SourceXmlPullParser::getComment() const {
+    return mEventQueue.front().comment;
+}
+
+size_t SourceXmlPullParser::getLineNumber() const {
+    return mEventQueue.front().lineNumber;
+}
+
+size_t SourceXmlPullParser::getDepth() const {
+    return mEventQueue.front().depth;
+}
+
+const std::u16string& SourceXmlPullParser::getText() const {
+    if (getEvent() != Event::kText) {
+        return mEmpty;
+    }
+    return mEventQueue.front().data1;
+}
+
+const std::u16string& SourceXmlPullParser::getNamespacePrefix() const {
+    const Event currentEvent = getEvent();
+    if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
+        return mEmpty;
+    }
+    return mEventQueue.front().data1;
+}
+
+const std::u16string& SourceXmlPullParser::getNamespaceUri() const {
+    const Event currentEvent = getEvent();
+    if (currentEvent != Event::kStartNamespace && currentEvent != Event::kEndNamespace) {
+        return mEmpty;
+    }
+    return mEventQueue.front().data2;
+}
+
+const std::u16string& SourceXmlPullParser::getElementNamespace() const {
+    const Event currentEvent = getEvent();
+    if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
+        return mEmpty;
+    }
+    return mEventQueue.front().data1;
+}
+
+const std::u16string& SourceXmlPullParser::getElementName() const {
+    const Event currentEvent = getEvent();
+    if (currentEvent != Event::kStartElement && currentEvent != Event::kEndElement) {
+        return mEmpty;
+    }
+    return mEventQueue.front().data2;
+}
+
+XmlPullParser::const_iterator SourceXmlPullParser::beginAttributes() const {
+    return mEventQueue.front().attributes.begin();
+}
+
+XmlPullParser::const_iterator SourceXmlPullParser::endAttributes() const {
+    return mEventQueue.front().attributes.end();
+}
+
+size_t SourceXmlPullParser::getAttributeCount() const {
+    if (getEvent() != Event::kStartElement) {
+        return 0;
+    }
+    return mEventQueue.front().attributes.size();
+}
+
+/**
+ * Extracts the namespace and name of an expanded element or attribute name.
+ */
+static void splitName(const char* name, std::u16string& outNs, std::u16string& outName) {
+    const char* p = name;
+    while (*p != 0 && *p != kXmlNamespaceSep) {
+        p++;
+    }
+
+    if (*p == 0) {
+        outNs = std::u16string();
+        outName = util::utf8ToUtf16(name);
+    } else {
+        outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
+        outName = util::utf8ToUtf16(p + 1);
+    }
+}
+
+void XMLCALL SourceXmlPullParser::startNamespaceHandler(void* userData, const char* prefix,
+        const char* uri) {
+    SourceXmlPullParser* parser = reinterpret_cast<SourceXmlPullParser*>(userData);
+    std::u16string namespaceUri = uri != nullptr ? util::utf8ToUtf16(uri) : std::u16string();
+    parser->mNamespaceUris.push(namespaceUri);
+    parser->mEventQueue.push(EventData{
+            Event::kStartNamespace,
+            XML_GetCurrentLineNumber(parser->mParser),
+            parser->mDepth++,
+            prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
+            namespaceUri
+    });
+}
+
+void XMLCALL SourceXmlPullParser::startElementHandler(void* userData, const char* name,
+        const char** attrs) {
+    SourceXmlPullParser* parser = reinterpret_cast<SourceXmlPullParser*>(userData);
+
+    EventData data = {
+            Event::kStartElement, XML_GetCurrentLineNumber(parser->mParser), parser->mDepth++
+    };
+    splitName(name, data.data1, data.data2);
+
+    while (*attrs) {
+        Attribute attribute;
+        splitName(*attrs++, attribute.namespaceUri, attribute.name);
+        attribute.value = util::utf8ToUtf16(*attrs++);
+
+        // Insert in sorted order.
+        auto iter = std::lower_bound(data.attributes.begin(), data.attributes.end(), attribute);
+        data.attributes.insert(iter, std::move(attribute));
+    }
+
+    // Move the structure into the queue (no copy).
+    parser->mEventQueue.push(std::move(data));
+}
+
+void XMLCALL SourceXmlPullParser::characterDataHandler(void* userData, const char* s, int len) {
+    SourceXmlPullParser* parser = reinterpret_cast<SourceXmlPullParser*>(userData);
+
+    parser->mEventQueue.push(EventData{
+            Event::kText,
+            XML_GetCurrentLineNumber(parser->mParser),
+            parser->mDepth,
+            util::utf8ToUtf16(StringPiece(s, len))
+    });
+}
+
+void XMLCALL SourceXmlPullParser::endElementHandler(void* userData, const char* name) {
+    SourceXmlPullParser* parser = reinterpret_cast<SourceXmlPullParser*>(userData);
+
+    EventData data = {
+            Event::kEndElement, XML_GetCurrentLineNumber(parser->mParser), --(parser->mDepth)
+    };
+    splitName(name, data.data1, data.data2);
+
+    // Move the data into the queue (no copy).
+    parser->mEventQueue.push(std::move(data));
+}
+
+void XMLCALL SourceXmlPullParser::endNamespaceHandler(void* userData, const char* prefix) {
+    SourceXmlPullParser* parser = reinterpret_cast<SourceXmlPullParser*>(userData);
+
+    parser->mEventQueue.push(EventData{
+            Event::kEndNamespace,
+            XML_GetCurrentLineNumber(parser->mParser),
+            --(parser->mDepth),
+            prefix != nullptr ? util::utf8ToUtf16(prefix) : std::u16string(),
+            parser->mNamespaceUris.top()
+    });
+    parser->mNamespaceUris.pop();
+}
+
+void XMLCALL SourceXmlPullParser::commentDataHandler(void* userData, const char* comment) {
+    SourceXmlPullParser* parser = reinterpret_cast<SourceXmlPullParser*>(userData);
+
+    parser->mEventQueue.push(EventData{
+            Event::kComment,
+            XML_GetCurrentLineNumber(parser->mParser),
+            parser->mDepth,
+            util::utf8ToUtf16(comment)
+    });
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/SourceXmlPullParser.h b/tools/aapt2/SourceXmlPullParser.h
new file mode 100644
index 0000000..ba904ba
--- /dev/null
+++ b/tools/aapt2/SourceXmlPullParser.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_SOURCE_XML_PULL_PARSER_H
+#define AAPT_SOURCE_XML_PULL_PARSER_H
+
+#include <istream>
+#include <libexpat/expat.h>
+#include <queue>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "XmlPullParser.h"
+
+namespace aapt {
+
+class SourceXmlPullParser : public XmlPullParser {
+public:
+    SourceXmlPullParser(std::istream& in);
+    SourceXmlPullParser(const SourceXmlPullParser& rhs) = delete;
+    ~SourceXmlPullParser();
+
+    Event getEvent() const;
+    const std::string& getLastError() const;
+    Event next();
+
+    const std::u16string& getComment() const;
+    size_t getLineNumber() const;
+    size_t getDepth() const;
+
+    const std::u16string& getText() const;
+
+    const std::u16string& getNamespacePrefix() const;
+    const std::u16string& getNamespaceUri() const;
+
+    const std::u16string& getElementNamespace() const;
+    const std::u16string& getElementName() const;
+
+    const_iterator beginAttributes() const;
+    const_iterator endAttributes() const;
+    size_t getAttributeCount() const;
+
+private:
+    static void XMLCALL startNamespaceHandler(void* userData, const char* prefix, const char* uri);
+    static void XMLCALL startElementHandler(void* userData, const char* name, const char** attrs);
+    static void XMLCALL characterDataHandler(void* userData, const char* s, int len);
+    static void XMLCALL endElementHandler(void* userData, const char* name);
+    static void XMLCALL endNamespaceHandler(void* userData, const char* prefix);
+    static void XMLCALL commentDataHandler(void* userData, const char* comment);
+
+    struct EventData {
+        Event event;
+        size_t lineNumber;
+        size_t depth;
+        std::u16string data1;
+        std::u16string data2;
+        std::u16string comment;
+        std::vector<Attribute> attributes;
+    };
+
+    std::istream& mIn;
+    XML_Parser mParser;
+    char mBuffer[16384];
+    std::queue<EventData> mEventQueue;
+    std::string mLastError;
+    const std::u16string mEmpty;
+    size_t mDepth;
+    std::stack<std::u16string> mNamespaceUris;
+};
+
+} // namespace aapt
+
+#endif // AAPT_SOURCE_XML_PULL_PARSER_H
diff --git a/tools/aapt2/StringPiece.h b/tools/aapt2/StringPiece.h
new file mode 100644
index 0000000..e2a1597
--- /dev/null
+++ b/tools/aapt2/StringPiece.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_STRING_PIECE_H
+#define AAPT_STRING_PIECE_H
+
+#include <ostream>
+#include <string>
+#include <utils/String8.h>
+#include <utils/Unicode.h>
+
+namespace aapt {
+
+/**
+ * Read only wrapper around basic C strings.
+ * Prevents excessive copying.
+ *
+ * WARNING: When creating from std::basic_string<>, moving the original
+ * std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
+ * BasicStringPiece<> should only be used transitively.
+ */
+template <typename TChar>
+class BasicStringPiece {
+public:
+    using const_iterator = const TChar*;
+
+    BasicStringPiece();
+    BasicStringPiece(const BasicStringPiece<TChar>& str);
+    BasicStringPiece(const std::basic_string<TChar>& str);
+    BasicStringPiece(const TChar* str);
+    BasicStringPiece(const TChar* str, size_t len);
+
+    BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
+    BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
+
+    BasicStringPiece<TChar> substr(size_t start, size_t len) const;
+    BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
+                                   BasicStringPiece<TChar>::const_iterator end) const;
+
+    const TChar* data() const;
+    size_t length() const;
+    size_t size() const;
+    bool empty() const;
+    std::basic_string<TChar> toString() const;
+
+    int compare(const BasicStringPiece<TChar>& rhs) const;
+    bool operator<(const BasicStringPiece<TChar>& rhs) const;
+    bool operator>(const BasicStringPiece<TChar>& rhs) const;
+    bool operator==(const BasicStringPiece<TChar>& rhs) const;
+    bool operator!=(const BasicStringPiece<TChar>& rhs) const;
+
+    const_iterator begin() const;
+    const_iterator end() const;
+
+private:
+    const TChar* mData;
+    size_t mLength;
+};
+
+using StringPiece = BasicStringPiece<char>;
+using StringPiece16 = BasicStringPiece<char16_t>;
+
+//
+// BasicStringPiece implementation.
+//
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece() : mData(nullptr) , mLength(0) {
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str) :
+        mData(str.mData), mLength(str.mLength) {
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str) :
+        mData(str.data()), mLength(str.length()) {
+}
+
+template <>
+inline BasicStringPiece<char>::BasicStringPiece(const char* str) :
+        mData(str), mLength(str != nullptr ? strlen(str) : 0) {
+}
+
+template <>
+inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str) :
+        mData(str), mLength(str != nullptr ? strlen16(str) : 0) {
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len) :
+        mData(str), mLength(len) {
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
+        const BasicStringPiece<TChar>& rhs) {
+    mData = rhs.mData;
+    mLength = rhs.mLength;
+    return *this;
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
+    mData = str;
+    mLength = len;
+    return *this;
+}
+
+
+template <typename TChar>
+inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
+    if (start + len > mLength) {
+        return BasicStringPiece<TChar>();
+    }
+    return BasicStringPiece<TChar>(mData + start, len);
+}
+
+template <typename TChar>
+inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
+        BasicStringPiece<TChar>::const_iterator begin,
+        BasicStringPiece<TChar>::const_iterator end) const {
+    return BasicStringPiece<TChar>(begin, end - begin);
+}
+
+template <typename TChar>
+inline const TChar* BasicStringPiece<TChar>::data() const {
+    return mData;
+}
+
+template <typename TChar>
+inline size_t BasicStringPiece<TChar>::length() const {
+    return mLength;
+}
+
+template <typename TChar>
+inline size_t BasicStringPiece<TChar>::size() const {
+    return mLength;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::empty() const {
+    return mLength == 0;
+}
+
+template <typename TChar>
+inline std::basic_string<TChar> BasicStringPiece<TChar>::toString() const {
+    return std::basic_string<TChar>(mData, mLength);
+}
+
+template <>
+inline int BasicStringPiece<char>::compare(const BasicStringPiece<char>& rhs) const {
+    const char nullStr = '\0';
+    const char* b1 = mData != nullptr ? mData : &nullStr;
+    const char* e1 = b1 + mLength;
+    const char* b2 = rhs.mData != nullptr ? rhs.mData : &nullStr;
+    const char* e2 = b2 + rhs.mLength;
+
+    while (b1 < e1 && b2 < e2) {
+        const int d = static_cast<int>(*b1++) - static_cast<int>(*b2++);
+        if (d) {
+            return d;
+        }
+    }
+    return static_cast<int>(mLength - rhs.mLength);
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char16_t>& str) {
+    android::String8 utf8(str.data(), str.size());
+    return out.write(utf8.string(), utf8.size());
+}
+
+
+template <>
+inline int BasicStringPiece<char16_t>::compare(const BasicStringPiece<char16_t>& rhs) const {
+    const char16_t nullStr = u'\0';
+    const char16_t* b1 = mData != nullptr ? mData : &nullStr;
+    const char16_t* b2 = rhs.mData != nullptr ? rhs.mData : &nullStr;
+    return strzcmp16(b1, mLength, b2, rhs.mLength);
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
+    return compare(rhs) < 0;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
+    return compare(rhs) > 0;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
+    return compare(rhs) == 0;
+}
+
+template <typename TChar>
+inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
+    return compare(rhs) != 0;
+}
+
+template <typename TChar>
+inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
+    return mData;
+}
+
+template <typename TChar>
+inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
+    return mData + mLength;
+}
+
+inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
+    return out.write(str.data(), str.size());
+}
+
+} // namespace aapt
+
+#endif // AAPT_STRING_PIECE_H
diff --git a/tools/aapt2/StringPiece_test.cpp b/tools/aapt2/StringPiece_test.cpp
new file mode 100644
index 0000000..43f7a37
--- /dev/null
+++ b/tools/aapt2/StringPiece_test.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <gtest/gtest.h>
+#include <string>
+#include <vector>
+
+#include "StringPiece.h"
+
+namespace aapt {
+
+TEST(StringPieceTest, CompareNonNullTerminatedPiece) {
+    StringPiece a("hello world", 5);
+    StringPiece b("hello moon", 5);
+    EXPECT_EQ(a, b);
+
+    StringPiece16 a16(u"hello world", 5);
+    StringPiece16 b16(u"hello moon", 5);
+    EXPECT_EQ(a16, b16);
+}
+
+TEST(StringPieceTest, PiecesHaveCorrectSortOrder) {
+    std::u16string testing(u"testing");
+    std::u16string banana(u"banana");
+    std::u16string car(u"car");
+
+    EXPECT_TRUE(StringPiece16(testing) > banana);
+    EXPECT_TRUE(StringPiece16(testing) > car);
+    EXPECT_TRUE(StringPiece16(banana) < testing);
+    EXPECT_TRUE(StringPiece16(banana) < car);
+    EXPECT_TRUE(StringPiece16(car) < testing);
+    EXPECT_TRUE(StringPiece16(car) > banana);
+}
+
+TEST(StringPieceTest, PiecesHaveCorrectSortOrderUtf8) {
+    std::string testing("testing");
+    std::string banana("banana");
+    std::string car("car");
+
+    EXPECT_TRUE(StringPiece(testing) > banana);
+    EXPECT_TRUE(StringPiece(testing) > car);
+    EXPECT_TRUE(StringPiece(banana) < testing);
+    EXPECT_TRUE(StringPiece(banana) < car);
+    EXPECT_TRUE(StringPiece(car) < testing);
+    EXPECT_TRUE(StringPiece(car) > banana);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/StringPool.cpp b/tools/aapt2/StringPool.cpp
new file mode 100644
index 0000000..b159a00
--- /dev/null
+++ b/tools/aapt2/StringPool.cpp
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BigBuffer.h"
+#include "StringPiece.h"
+#include "StringPool.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <androidfw/ResourceTypes.h>
+#include <memory>
+#include <string>
+
+namespace aapt {
+
+StringPool::Ref::Ref() : mEntry(nullptr) {
+}
+
+StringPool::Ref::Ref(const StringPool::Ref& rhs) : mEntry(rhs.mEntry) {
+    if (mEntry != nullptr) {
+        mEntry->ref++;
+    }
+}
+
+StringPool::Ref::Ref(StringPool::Entry* entry) : mEntry(entry) {
+    if (mEntry != nullptr) {
+        mEntry->ref++;
+    }
+}
+
+StringPool::Ref::~Ref() {
+    if (mEntry != nullptr) {
+        mEntry->ref--;
+    }
+}
+
+StringPool::Ref& StringPool::Ref::operator=(const StringPool::Ref& rhs) {
+    if (rhs.mEntry != nullptr) {
+        rhs.mEntry->ref++;
+    }
+
+    if (mEntry != nullptr) {
+        mEntry->ref--;
+    }
+    mEntry = rhs.mEntry;
+    return *this;
+}
+
+const std::u16string* StringPool::Ref::operator->() const {
+    return &mEntry->value;
+}
+
+const std::u16string& StringPool::Ref::operator*() const {
+    return mEntry->value;
+}
+
+size_t StringPool::Ref::getIndex() const {
+    return mEntry->index;
+}
+
+const StringPool::Context& StringPool::Ref::getContext() const {
+    return mEntry->context;
+}
+
+StringPool::StyleRef::StyleRef() : mEntry(nullptr) {
+}
+
+StringPool::StyleRef::StyleRef(const StringPool::StyleRef& rhs) : mEntry(rhs.mEntry) {
+    if (mEntry != nullptr) {
+        mEntry->ref++;
+    }
+}
+
+StringPool::StyleRef::StyleRef(StringPool::StyleEntry* entry) : mEntry(entry) {
+    if (mEntry != nullptr) {
+        mEntry->ref++;
+    }
+}
+
+StringPool::StyleRef::~StyleRef() {
+    if (mEntry != nullptr) {
+        mEntry->ref--;
+    }
+}
+
+StringPool::StyleRef& StringPool::StyleRef::operator=(const StringPool::StyleRef& rhs) {
+    if (rhs.mEntry != nullptr) {
+        rhs.mEntry->ref++;
+    }
+
+    if (mEntry != nullptr) {
+        mEntry->ref--;
+    }
+    mEntry = rhs.mEntry;
+    return *this;
+}
+
+const StringPool::StyleEntry* StringPool::StyleRef::operator->() const {
+    return mEntry;
+}
+
+const StringPool::StyleEntry& StringPool::StyleRef::operator*() const {
+    return *mEntry;
+}
+
+size_t StringPool::StyleRef::getIndex() const {
+    return mEntry->str.getIndex();
+}
+
+const StringPool::Context& StringPool::StyleRef::getContext() const {
+    return mEntry->str.getContext();
+}
+
+StringPool::Ref StringPool::makeRef(const StringPiece16& str) {
+    return makeRefImpl(str, Context{}, true);
+}
+
+StringPool::Ref StringPool::makeRef(const StringPiece16& str, const Context& context) {
+    return makeRefImpl(str, context, true);
+}
+
+StringPool::Ref StringPool::makeRefImpl(const StringPiece16& str, const Context& context,
+        bool unique) {
+    if (unique) {
+        auto iter = mIndexedStrings.find(str);
+        if (iter != std::end(mIndexedStrings)) {
+            return Ref(iter->second);
+        }
+    }
+
+    Entry* entry = new Entry();
+    entry->value = str.toString();
+    entry->context = context;
+    entry->index = mStrings.size();
+    entry->ref = 0;
+    mStrings.emplace_back(entry);
+    mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry));
+    return Ref(entry);
+}
+
+StringPool::StyleRef StringPool::makeRef(const StyleString& str) {
+    return makeRef(str, Context{});
+}
+
+StringPool::StyleRef StringPool::makeRef(const StyleString& str, const Context& context) {
+    Entry* entry = new Entry();
+    entry->value = str.str;
+    entry->context = context;
+    entry->index = mStrings.size();
+    entry->ref = 0;
+    mStrings.emplace_back(entry);
+    mIndexedStrings.insert(std::make_pair(StringPiece16(entry->value), entry));
+
+    StyleEntry* styleEntry = new StyleEntry();
+    styleEntry->str = Ref(entry);
+    for (const aapt::Span& span : str.spans) {
+        styleEntry->spans.emplace_back(Span{makeRef(span.name),
+                span.firstChar, span.lastChar});
+    }
+    styleEntry->ref = 0;
+    mStyles.emplace_back(styleEntry);
+    return StyleRef(styleEntry);
+}
+
+void StringPool::merge(StringPool&& pool) {
+    mIndexedStrings.insert(pool.mIndexedStrings.begin(), pool.mIndexedStrings.end());
+    pool.mIndexedStrings.clear();
+    std::move(pool.mStrings.begin(), pool.mStrings.end(), std::back_inserter(mStrings));
+    pool.mStrings.clear();
+    std::move(pool.mStyles.begin(), pool.mStyles.end(), std::back_inserter(mStyles));
+    pool.mStyles.clear();
+
+    // Assign the indices.
+    const size_t len = mStrings.size();
+    for (size_t index = 0; index < len; index++) {
+        mStrings[index]->index = index;
+    }
+}
+
+void StringPool::hintWillAdd(size_t stringCount, size_t styleCount) {
+    mStrings.reserve(mStrings.size() + stringCount);
+    mStyles.reserve(mStyles.size() + styleCount);
+}
+
+void StringPool::prune() {
+    const auto iterEnd = std::end(mIndexedStrings);
+    auto indexIter = std::begin(mIndexedStrings);
+    while (indexIter != iterEnd) {
+        if (indexIter->second->ref <= 0) {
+            mIndexedStrings.erase(indexIter++);
+        } else {
+            ++indexIter;
+        }
+    }
+
+    auto endIter2 = std::remove_if(std::begin(mStrings), std::end(mStrings),
+            [](const std::unique_ptr<Entry>& entry) -> bool {
+                return entry->ref <= 0;
+            }
+    );
+
+    auto endIter3 = std::remove_if(std::begin(mStyles), std::end(mStyles),
+            [](const std::unique_ptr<StyleEntry>& entry) -> bool {
+                return entry->ref <= 0;
+            }
+    );
+
+    // Remove the entries at the end or else we'll be accessing
+    // a deleted string from the StyleEntry.
+    mStrings.erase(endIter2, std::end(mStrings));
+    mStyles.erase(endIter3, std::end(mStyles));
+}
+
+void StringPool::sort(const std::function<bool(const Entry&, const Entry&)>& cmp) {
+    std::sort(std::begin(mStrings), std::end(mStrings),
+            [&cmp](const std::unique_ptr<Entry>& a, const std::unique_ptr<Entry>& b) -> bool {
+                return cmp(*a, *b);
+            }
+    );
+
+    // Assign the indices.
+    const size_t len = mStrings.size();
+    for (size_t index = 0; index < len; index++) {
+        mStrings[index]->index = index;
+    }
+
+    // Reorder the styles.
+    std::sort(std::begin(mStyles), std::end(mStyles),
+            [](const std::unique_ptr<StyleEntry>& lhs,
+               const std::unique_ptr<StyleEntry>& rhs) -> bool {
+                return lhs->str.getIndex() < rhs->str.getIndex();
+            }
+    );
+}
+
+static uint8_t* encodeLength(uint8_t* data, size_t length) {
+    if (length > 0x7fu) {
+        *data++ = 0x80u | (0x000000ffu & (length >> 8));
+    }
+    *data++ = 0x000000ffu & length;
+    return data;
+}
+
+static size_t encodedLengthByteCount(size_t length) {
+    return length > 0x7fu ? 2 : 1;
+}
+
+bool StringPool::flattenUtf8(BigBuffer* out, const StringPool& pool) {
+    const size_t startIndex = out->size();
+    android::ResStringPool_header* header = out->nextBlock<android::ResStringPool_header>();
+    header->header.type = android::RES_STRING_POOL_TYPE;
+    header->header.headerSize = sizeof(*header);
+    header->stringCount = pool.size();
+    header->flags |= android::ResStringPool_header::UTF8_FLAG;
+
+    uint32_t* indices = out->nextBlock<uint32_t>(pool.size());
+
+    uint32_t* styleIndices = nullptr;
+    if (!pool.mStyles.empty()) {
+        header->styleCount = pool.mStyles.back()->str.getIndex() + 1;
+        styleIndices = out->nextBlock<uint32_t>(header->styleCount);
+    }
+
+    const size_t beforeStringsIndex = out->size();
+    header->stringsStart = beforeStringsIndex - startIndex;
+
+    for (const auto& entry : pool) {
+        *indices = out->size() - beforeStringsIndex;
+        indices++;
+
+        std::string encoded = util::utf16ToUtf8(entry->value);
+
+        const size_t stringByteLength = sizeof(char) * encoded.length();
+        const size_t totalSize = encodedLengthByteCount(entry->value.size())
+                + encodedLengthByteCount(encoded.length())
+                + stringByteLength
+                + sizeof(char);
+
+        uint8_t* data = out->nextBlock<uint8_t>(totalSize);
+
+        // First encode the actual UTF16 string length.
+        data = encodeLength(data, entry->value.size());
+
+        // Now encode the size of the converted UTF8 string.
+        data = encodeLength(data, encoded.length());
+
+        memcpy(data, encoded.data(), stringByteLength);
+        data += stringByteLength;
+        *data = 0;
+    }
+
+    out->align4();
+
+    if (!pool.mStyles.empty()) {
+        const size_t beforeStylesIndex = out->size();
+        header->stylesStart = beforeStylesIndex - startIndex;
+
+        size_t currentIndex = 0;
+        for (const auto& entry : pool.mStyles) {
+            while (entry->str.getIndex() > currentIndex) {
+                styleIndices[currentIndex++] = out->size() - beforeStylesIndex;
+
+                uint32_t* spanOffset = out->nextBlock<uint32_t>();
+                *spanOffset = android::ResStringPool_span::END;
+            }
+            styleIndices[currentIndex++] = out->size() - beforeStylesIndex;
+
+            android::ResStringPool_span* span =
+                    out->nextBlock<android::ResStringPool_span>(entry->spans.size());
+            for (const auto& s : entry->spans) {
+                span->name.index = s.name.getIndex();
+                span->firstChar = s.firstChar;
+                span->lastChar = s.lastChar;
+                span++;
+            }
+
+            uint32_t* spanEnd = out->nextBlock<uint32_t>();
+            *spanEnd = android::ResStringPool_span::END;
+        }
+
+        // The error checking code in the platform looks for an entire
+        // ResStringPool_span structure worth of 0xFFFFFFFF at the end
+        // of the style block, so fill in the remaining 2 32bit words
+        // with 0xFFFFFFFF.
+        const size_t paddingLength = sizeof(android::ResStringPool_span)
+                - sizeof(android::ResStringPool_span::name);
+        uint8_t* padding = out->nextBlock<uint8_t>(paddingLength);
+        memset(padding, 0xff, paddingLength);
+        out->align4();
+    }
+    header->header.size = out->size() - startIndex;
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/StringPool.h b/tools/aapt2/StringPool.h
new file mode 100644
index 0000000..2aa5b65
--- /dev/null
+++ b/tools/aapt2/StringPool.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_STRING_POOL_H
+#define AAPT_STRING_POOL_H
+
+#include "BigBuffer.h"
+#include "ConfigDescription.h"
+#include "StringPiece.h"
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+struct Span {
+    std::u16string name;
+    uint32_t firstChar;
+    uint32_t lastChar;
+};
+
+struct StyleString {
+    std::u16string str;
+    std::vector<Span> spans;
+};
+
+class StringPool {
+public:
+    struct Context {
+        uint32_t priority;
+        ConfigDescription config;
+    };
+
+    class Entry;
+
+    class Ref {
+    public:
+        Ref();
+        Ref(const Ref&);
+        ~Ref();
+
+        Ref& operator=(const Ref& rhs);
+        const std::u16string* operator->() const;
+        const std::u16string& operator*() const;
+
+        size_t getIndex() const;
+        const Context& getContext() const;
+
+    private:
+        friend class StringPool;
+
+        Ref(Entry* entry);
+
+        Entry* mEntry;
+    };
+
+    class StyleEntry;
+
+    class StyleRef {
+    public:
+        StyleRef();
+        StyleRef(const StyleRef&);
+        ~StyleRef();
+
+        StyleRef& operator=(const StyleRef& rhs);
+        const StyleEntry* operator->() const;
+        const StyleEntry& operator*() const;
+
+        size_t getIndex() const;
+        const Context& getContext() const;
+
+    private:
+        friend class StringPool;
+
+        StyleRef(StyleEntry* entry);
+
+        StyleEntry* mEntry;
+    };
+
+    class Entry {
+    public:
+        std::u16string value;
+        Context context;
+        size_t index;
+
+    private:
+        friend class StringPool;
+        friend class Ref;
+
+        int ref;
+    };
+
+    struct Span {
+        Ref name;
+        uint32_t firstChar;
+        uint32_t lastChar;
+    };
+
+    class StyleEntry {
+    public:
+        Ref str;
+        std::vector<Span> spans;
+
+    private:
+        friend class StringPool;
+        friend class StyleRef;
+
+        int ref;
+    };
+
+    using const_iterator = std::vector<std::unique_ptr<Entry>>::const_iterator;
+
+    static bool flattenUtf8(BigBuffer* out, const StringPool& pool);
+    static bool flatten(BigBuffer* out, const StringPool& pool);
+
+    StringPool() = default;
+    StringPool(const StringPool&) = delete;
+
+    /**
+     * Adds a string to the pool, unless it already exists. Returns
+     * a reference to the string in the pool.
+     */
+    Ref makeRef(const StringPiece16& str);
+
+    /**
+     * Adds a string to the pool, unless it already exists, with a context
+     * object that can be used when sorting the string pool. Returns
+     * a reference to the string in the pool.
+     */
+    Ref makeRef(const StringPiece16& str, const Context& context);
+
+    /**
+     * Adds a style to the string pool and returns a reference to it.
+     */
+    StyleRef makeRef(const StyleString& str);
+
+    /**
+     * Adds a style to the string pool with a context object that
+     * can be used when sorting the string pool. Returns a reference
+     * to the style in the string pool.
+     */
+    StyleRef makeRef(const StyleString& str, const Context& context);
+
+    /**
+     * Moves pool into this one without coalescing strings. When this
+     * function returns, pool will be empty.
+     */
+    void merge(StringPool&& pool);
+
+    /**
+     * Retuns the number of strings in the table.
+     */
+    inline size_t size() const;
+
+    /**
+     * Reserves space for strings and styles as an optimization.
+     */
+    void hintWillAdd(size_t stringCount, size_t styleCount);
+
+    /**
+     * Sorts the strings according to some comparison function.
+     */
+    void sort(const std::function<bool(const Entry&, const Entry&)>& cmp);
+
+    /**
+     * Removes any strings that have no references.
+     */
+    void prune();
+
+private:
+    friend const_iterator begin(const StringPool& pool);
+    friend const_iterator end(const StringPool& pool);
+
+    Ref makeRefImpl(const StringPiece16& str, const Context& context, bool unique);
+
+    std::vector<std::unique_ptr<Entry>> mStrings;
+    std::vector<std::unique_ptr<StyleEntry>> mStyles;
+    std::multimap<StringPiece16, Entry*> mIndexedStrings;
+};
+
+//
+// Inline implementation
+//
+
+inline size_t StringPool::size() const {
+    return mStrings.size();
+}
+
+inline StringPool::const_iterator begin(const StringPool& pool) {
+    return pool.mStrings.begin();
+}
+
+inline StringPool::const_iterator end(const StringPool& pool) {
+    return pool.mStrings.end();
+}
+
+} // namespace aapt
+
+#endif // AAPT_STRING_POOL_H
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
new file mode 100644
index 0000000..85d101a
--- /dev/null
+++ b/tools/aapt2/StringPool_test.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "StringPool.h"
+#include "Util.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+using namespace android;
+
+namespace aapt {
+
+TEST(StringPoolTest, InsertOneString) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"wut");
+    EXPECT_EQ(*ref, u"wut");
+}
+
+TEST(StringPoolTest, InsertTwoUniqueStrings) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"wut");
+    StringPool::Ref ref2 = pool.makeRef(u"hey");
+
+    EXPECT_EQ(*ref, u"wut");
+    EXPECT_EQ(*ref2, u"hey");
+}
+
+TEST(StringPoolTest, DoNotInsertNewDuplicateString) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"wut");
+    StringPool::Ref ref2 = pool.makeRef(u"wut");
+
+    EXPECT_EQ(*ref, u"wut");
+    EXPECT_EQ(*ref2, u"wut");
+    EXPECT_EQ(1u, pool.size());
+}
+
+TEST(StringPoolTest, MaintainInsertionOrderIndex) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"z");
+    StringPool::Ref ref2 = pool.makeRef(u"a");
+    StringPool::Ref ref3 = pool.makeRef(u"m");
+
+    EXPECT_EQ(0u, ref.getIndex());
+    EXPECT_EQ(1u, ref2.getIndex());
+    EXPECT_EQ(2u, ref3.getIndex());
+}
+
+TEST(StringPoolTest, PruneStringsWithNoReferences) {
+    StringPool pool;
+
+    {
+        StringPool::Ref ref = pool.makeRef(u"wut");
+        EXPECT_EQ(*ref, u"wut");
+        EXPECT_EQ(1u, pool.size());
+    }
+
+    EXPECT_EQ(1u, pool.size());
+    pool.prune();
+    EXPECT_EQ(0u, pool.size());
+}
+
+TEST(StringPoolTest, SortAndMaintainIndexesInReferences) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"z");
+    StringPool::StyleRef ref2 = pool.makeRef(StyleString{ {u"a"} });
+    StringPool::Ref ref3 = pool.makeRef(u"m");
+
+    EXPECT_EQ(*ref, u"z");
+    EXPECT_EQ(0u, ref.getIndex());
+
+    EXPECT_EQ(*(ref2->str), u"a");
+    EXPECT_EQ(1u, ref2.getIndex());
+
+    EXPECT_EQ(*ref3, u"m");
+    EXPECT_EQ(2u, ref3.getIndex());
+
+    pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
+        return a.value < b.value;
+    });
+
+
+    EXPECT_EQ(*ref, u"z");
+    EXPECT_EQ(2u, ref.getIndex());
+
+    EXPECT_EQ(*(ref2->str), u"a");
+    EXPECT_EQ(0u, ref2.getIndex());
+
+    EXPECT_EQ(*ref3, u"m");
+    EXPECT_EQ(1u, ref3.getIndex());
+}
+
+TEST(StringPoolTest, SortAndStillDedupe) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"z");
+    StringPool::Ref ref2 = pool.makeRef(u"a");
+    StringPool::Ref ref3 = pool.makeRef(u"m");
+
+    pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
+        return a.value < b.value;
+    });
+
+    StringPool::Ref ref4 = pool.makeRef(u"z");
+    StringPool::Ref ref5 = pool.makeRef(u"a");
+    StringPool::Ref ref6 = pool.makeRef(u"m");
+
+    EXPECT_EQ(ref4.getIndex(), ref.getIndex());
+    EXPECT_EQ(ref5.getIndex(), ref2.getIndex());
+    EXPECT_EQ(ref6.getIndex(), ref3.getIndex());
+}
+
+TEST(StringPoolTest, AddStyles) {
+    StringPool pool;
+
+    StyleString str {
+        { u"android" },
+        {
+            Span{ { u"b" }, 2, 6 }
+        }
+    };
+
+    StringPool::StyleRef ref = pool.makeRef(str);
+
+    EXPECT_EQ(0u, ref.getIndex());
+    EXPECT_EQ(std::u16string(u"android"), *(ref->str));
+    ASSERT_EQ(1u, ref->spans.size());
+
+    const StringPool::Span& span = ref->spans.front();
+    EXPECT_EQ(*(span.name), u"b");
+    EXPECT_EQ(2u, span.firstChar);
+    EXPECT_EQ(6u, span.lastChar);
+}
+
+TEST(StringPoolTest, DoNotDedupeStyleWithSameStringAsNonStyle) {
+    StringPool pool;
+
+    StringPool::Ref ref = pool.makeRef(u"android");
+
+    StyleString str { { u"android" } };
+    StringPool::StyleRef styleRef = pool.makeRef(str);
+
+    EXPECT_NE(ref.getIndex(), styleRef.getIndex());
+}
+
+constexpr const char16_t* sLongString = u"バッテリーを長持ちさせるため、バッテリーセーバーは端末のパフォーマンスを抑え、バイブレーション、位置情報サービス、大半のバックグラウンドデータを制限します。メール、SMSや、同期を使 用するその他のアプリは、起動しても更新されないことがあります。バッテリーセーバーは端末の充電中は自動的にOFFになります。";
+
+TEST(StringPoolTest, FlattenUtf8) {
+    StringPool pool;
+
+    StringPool::Ref ref1 = pool.makeRef(u"hello");
+    StringPool::Ref ref2 = pool.makeRef(u"goodbye");
+    StringPool::Ref ref3 = pool.makeRef(sLongString);
+    StringPool::StyleRef ref4 = pool.makeRef(StyleString{
+            { u"style" },
+            { Span{ { u"b" }, 0, 1 }, Span{ { u"i" }, 2, 3 } }
+    });
+
+    EXPECT_EQ(0u, ref1.getIndex());
+    EXPECT_EQ(1u, ref2.getIndex());
+    EXPECT_EQ(2u, ref3.getIndex());
+    EXPECT_EQ(3u, ref4.getIndex());
+
+    BigBuffer buffer(1024);
+    StringPool::flattenUtf8(&buffer, pool);
+
+    uint8_t* data = new uint8_t[buffer.size()];
+    uint8_t* p = data;
+    for (const auto& b : buffer) {
+        memcpy(p, b.buffer.get(), b.size);
+        p += b.size;
+    }
+
+    {
+        ResStringPool test;
+        ASSERT_TRUE(test.setTo(data, buffer.size()) == NO_ERROR);
+
+        EXPECT_EQ(util::getString(test, 0), u"hello");
+        EXPECT_EQ(util::getString(test, 1), u"goodbye");
+        EXPECT_EQ(util::getString(test, 2), sLongString);
+        EXPECT_EQ(util::getString(test, 3), u"style");
+
+        const ResStringPool_span* span = test.styleAt(3);
+        ASSERT_NE(nullptr, span);
+        EXPECT_EQ(util::getString(test, span->name.index), u"b");
+        EXPECT_EQ(0u, span->firstChar);
+        EXPECT_EQ(1u, span->lastChar);
+        span++;
+
+        ASSERT_NE(ResStringPool_span::END, span->name.index);
+        EXPECT_EQ(util::getString(test, span->name.index), u"i");
+        EXPECT_EQ(2u, span->firstChar);
+        EXPECT_EQ(3u, span->lastChar);
+        span++;
+
+        EXPECT_EQ(ResStringPool_span::END, span->name.index);
+    }
+    delete[] data;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/TableFlattener.cpp b/tools/aapt2/TableFlattener.cpp
new file mode 100644
index 0000000..67c56e7
--- /dev/null
+++ b/tools/aapt2/TableFlattener.cpp
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BigBuffer.h"
+#include "ConfigDescription.h"
+#include "Logger.h"
+#include "ResourceTable.h"
+#include "ResourceTypeExtensions.h"
+#include "ResourceValues.h"
+#include "StringPool.h"
+#include "TableFlattener.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <androidfw/ResourceTypes.h>
+#include <sstream>
+
+namespace aapt {
+
+struct FlatEntry {
+    const ResourceEntry& entry;
+    const Value& value;
+    uint32_t entryKey;
+    uint32_t sourcePathKey;
+    uint32_t sourceLine;
+};
+
+/**
+ * Visitor that knows how to encode Map values.
+ */
+class MapFlattener : public ConstValueVisitor {
+public:
+    MapFlattener(BigBuffer* out, const FlatEntry& flatEntry,
+                 std::vector<std::pair<ResourceNameRef, uint32_t>>& symbols) :
+            mOut(out), mSymbols(symbols) {
+        mMap = mOut->nextBlock<android::ResTable_map_entry>();
+        mMap->key.index = flatEntry.entryKey;
+        mMap->flags = android::ResTable_entry::FLAG_COMPLEX;
+        if (flatEntry.entry.publicStatus.isPublic) {
+            mMap->flags |= android::ResTable_entry::FLAG_PUBLIC;
+        }
+        if (flatEntry.value.isWeak()) {
+            mMap->flags |= android::ResTable_entry::FLAG_WEAK;
+        }
+
+        ResTable_entry_source* sourceBlock = mOut->nextBlock<ResTable_entry_source>();
+        sourceBlock->pathIndex = flatEntry.sourcePathKey;
+        sourceBlock->line = flatEntry.sourceLine;
+
+        mMap->size = sizeof(*mMap) + sizeof(*sourceBlock);
+    }
+
+    void flattenParent(const Reference& ref) {
+        if (!ref.id.isValid()) {
+            mSymbols.push_back({
+                    ResourceNameRef(ref.name),
+                    (mOut->size() - mMap->size) + sizeof(*mMap) - sizeof(android::ResTable_entry)
+            });
+        }
+        mMap->parent.ident = ref.id.id;
+    }
+
+    void flattenEntry(const Reference& key, const Item& value) {
+        mMap->count++;
+
+        android::ResTable_map* outMapEntry = mOut->nextBlock<android::ResTable_map>();
+
+        // Write the key.
+        if (!Res_INTERNALID(key.id.id) && !key.id.isValid()) {
+            mSymbols.push_back(std::make_pair(ResourceNameRef(key.name),
+                    mOut->size() - sizeof(*outMapEntry)));
+        }
+        outMapEntry->name.ident = key.id.id;
+
+        // Write the value.
+        value.flatten(outMapEntry->value);
+
+        if (outMapEntry->value.data == 0x0) {
+            visitFunc<Reference>(value, [&](const Reference& reference) {
+                mSymbols.push_back(std::make_pair(ResourceNameRef(reference.name),
+                        mOut->size() - sizeof(outMapEntry->value.data)));
+            });
+        }
+        outMapEntry->value.size = sizeof(outMapEntry->value);
+    }
+
+    static bool compareStyleEntries(const Style::Entry* lhs, const Style::Entry* rhs) {
+        return lhs->key.id < rhs->key.id;
+    }
+
+    void visit(const Style& style, ValueVisitorArgs&) override {
+        if (style.parent.name.isValid()) {
+            flattenParent(style.parent);
+        }
+
+        // First sort the entries by ID.
+        std::vector<const Style::Entry*> sortedEntries;
+        for (const auto& styleEntry : style.entries) {
+            auto iter = std::lower_bound(sortedEntries.begin(), sortedEntries.end(),
+                    &styleEntry, compareStyleEntries);
+            sortedEntries.insert(iter, &styleEntry);
+        }
+
+        for (const Style::Entry* styleEntry : sortedEntries) {
+            flattenEntry(styleEntry->key, *styleEntry->value);
+        }
+    }
+
+    void visit(const Attribute& attr, ValueVisitorArgs&) override {
+        android::Res_value tempVal;
+        tempVal.dataType = android::Res_value::TYPE_INT_DEC;
+        tempVal.data = attr.typeMask;
+        flattenEntry(Reference(ResourceId{android::ResTable_map::ATTR_TYPE}),
+                BinaryPrimitive(tempVal));
+
+        for (const auto& symbol : attr.symbols) {
+            tempVal.data = symbol.value;
+            flattenEntry(symbol.symbol, BinaryPrimitive(tempVal));
+        }
+    }
+
+    void visit(const Styleable& styleable, ValueVisitorArgs&) override {
+        for (const auto& attr : styleable.entries) {
+            flattenEntry(attr, BinaryPrimitive(android::Res_value{}));
+        }
+    }
+
+    void visit(const Array& array, ValueVisitorArgs&) override {
+        for (const auto& item : array.items) {
+            flattenEntry({}, *item);
+        }
+    }
+
+    void visit(const Plural& plural, ValueVisitorArgs&) override {
+        const size_t count = plural.values.size();
+        for (size_t i = 0; i < count; i++) {
+            if (!plural.values[i]) {
+                continue;
+            }
+
+            ResourceId q;
+            switch (i) {
+                case Plural::Zero:
+                    q.id = android::ResTable_map::ATTR_ZERO;
+                    break;
+
+                case Plural::One:
+                    q.id = android::ResTable_map::ATTR_ONE;
+                    break;
+
+                case Plural::Two:
+                    q.id = android::ResTable_map::ATTR_TWO;
+                    break;
+
+                case Plural::Few:
+                    q.id = android::ResTable_map::ATTR_FEW;
+                    break;
+
+                case Plural::Many:
+                    q.id = android::ResTable_map::ATTR_MANY;
+                    break;
+
+                case Plural::Other:
+                    q.id = android::ResTable_map::ATTR_OTHER;
+                    break;
+
+                default:
+                    assert(false);
+                    break;
+            }
+
+            flattenEntry(Reference(q), *plural.values[i]);
+        }
+    }
+
+private:
+    BigBuffer* mOut;
+    std::vector<std::pair<ResourceNameRef, uint32_t>>& mSymbols;
+    android::ResTable_map_entry* mMap;
+};
+
+TableFlattener::TableFlattener(Options options)
+: mOptions(options) {
+}
+
+bool TableFlattener::flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
+        std::vector<std::pair<ResourceNameRef, uint32_t>>& symbolEntries) {
+    if (flatEntry.value.isItem()) {
+        android::ResTable_entry* entry = out->nextBlock<android::ResTable_entry>();
+
+        if (flatEntry.entry.publicStatus.isPublic) {
+            entry->flags |= android::ResTable_entry::FLAG_PUBLIC;
+        }
+
+        if (flatEntry.value.isWeak()) {
+            entry->flags |= android::ResTable_entry::FLAG_WEAK;
+        }
+
+        entry->key.index = flatEntry.entryKey;
+        entry->size = sizeof(*entry);
+
+        if (mOptions.useExtendedChunks) {
+            // Write the extra source block. This will be ignored by
+            // the Android runtime.
+            ResTable_entry_source* sourceBlock = out->nextBlock<ResTable_entry_source>();
+            sourceBlock->pathIndex = flatEntry.sourcePathKey;
+            sourceBlock->line = flatEntry.sourceLine;
+
+            entry->size += sizeof(*sourceBlock);
+        }
+
+        android::Res_value* outValue = out->nextBlock<android::Res_value>();
+
+        const Item& item = static_cast<const Item&>(flatEntry.value);
+        if (!item.flatten(*outValue)) {
+            return false;
+        }
+
+        if (outValue->data == 0x0) {
+            visitFunc<Reference>(item, [&](const Reference& reference) {
+                symbolEntries.push_back({
+                        ResourceNameRef(reference.name),
+                        out->size() - sizeof(outValue->data)
+                });
+            });
+        }
+        outValue->size = sizeof(*outValue);
+        return true;
+    }
+
+    MapFlattener flattener(out, flatEntry, symbolEntries);
+    flatEntry.value.accept(flattener, {});
+    return true;
+}
+
+bool TableFlattener::flatten(BigBuffer* out, const ResourceTable& table) {
+    const size_t beginning = out->size();
+
+    if (table.getPackage().size() == 0) {
+        Logger::error()
+                << "ResourceTable has no package name."
+                << std::endl;
+        return false;
+    }
+
+    if (table.getPackageId() == ResourceTable::kUnsetPackageId) {
+        Logger::error()
+                << "ResourceTable has no package ID set."
+                << std::endl;
+        return false;
+    }
+
+    std::vector<std::pair<ResourceNameRef, uint32_t>> symbolEntries;
+
+    StringPool typePool;
+    StringPool keyPool;
+    StringPool sourcePool;
+
+    // Sort the types by their IDs. They will be inserted into the StringPool
+    // in this order.
+    std::vector<ResourceTableType*> sortedTypes;
+    for (const auto& type : table) {
+        if (type->type == ResourceType::kStyleable && !mOptions.useExtendedChunks) {
+            continue;
+        }
+
+        auto iter = std::lower_bound(std::begin(sortedTypes), std::end(sortedTypes), type.get(),
+                [](const ResourceTableType* lhs, const ResourceTableType* rhs) -> bool {
+                    return lhs->typeId < rhs->typeId;
+                });
+        sortedTypes.insert(iter, type.get());
+    }
+
+    BigBuffer typeBlock(1024);
+    size_t expectedTypeId = 1;
+    for (const ResourceTableType* type : sortedTypes) {
+        if (type->typeId == ResourceTableType::kUnsetTypeId
+                || type->typeId == 0) {
+            Logger::error()
+                    << "resource type '"
+                    << type->type
+                    << "' from package '"
+                    << table.getPackage()
+                    << "' has no ID."
+                    << std::endl;
+            return false;
+        }
+
+        // If there is a gap in the type IDs, fill in the StringPool
+        // with empty values until we reach the ID we expect.
+        while (type->typeId > expectedTypeId) {
+            std::u16string typeName(u"?");
+            typeName += expectedTypeId;
+            typePool.makeRef(typeName);
+            expectedTypeId++;
+        }
+        expectedTypeId++;
+        typePool.makeRef(toString(type->type));
+
+        android::ResTable_typeSpec* spec = typeBlock.nextBlock<android::ResTable_typeSpec>();
+        spec->header.type = android::RES_TABLE_TYPE_SPEC_TYPE;
+        spec->header.headerSize = sizeof(*spec);
+        spec->header.size = spec->header.headerSize + (type->entries.size() * sizeof(uint32_t));
+        spec->id = type->typeId;
+        spec->entryCount = type->entries.size();
+
+        // Reserve space for the masks of each resource in this type. These
+        // show for which configuration axis the resource changes.
+        uint32_t* configMasks = typeBlock.nextBlock<uint32_t>(type->entries.size());
+
+        // Sort the entries by entry ID and write their configuration masks.
+        std::vector<ResourceEntry*> entries;
+        const size_t entryCount = type->entries.size();
+        for (size_t entryIndex = 0; entryIndex < entryCount; entryIndex++) {
+            const auto& entry = type->entries[entryIndex];
+
+            if (entry->entryId == ResourceEntry::kUnsetEntryId) {
+                Logger::error()
+                        << "resource '"
+                        << ResourceName{ table.getPackage(), type->type, entry->name }
+                        << "' has no ID."
+                        << std::endl;
+                return false;
+            }
+
+            auto iter = std::lower_bound(std::begin(entries), std::end(entries), entry.get(),
+                    [](const ResourceEntry* lhs, const ResourceEntry* rhs) -> bool {
+                        return lhs->entryId < rhs->entryId;
+                    });
+            entries.insert(iter, entry.get());
+
+            // Populate the config masks for this entry.
+            if (entry->publicStatus.isPublic) {
+                configMasks[entry->entryId] |= android::ResTable_typeSpec::SPEC_PUBLIC;
+            }
+
+            const size_t configCount = entry->values.size();
+            for (size_t i = 0; i < configCount; i++) {
+                const ConfigDescription& config = entry->values[i].config;
+                for (size_t j = i + 1; j < configCount; j++) {
+                    configMasks[entry->entryId] |= config.diff(entry->values[j].config);
+                }
+            }
+        }
+
+        // The binary resource table lists resource entries for each configuration.
+        // We store them inverted, where a resource entry lists the values for each
+        // configuration available. Here we reverse this to match the binary table.
+        std::map<ConfigDescription, std::vector<FlatEntry>> data;
+        for (const ResourceEntry* entry : entries) {
+            size_t keyIndex = keyPool.makeRef(entry->name).getIndex();
+
+            if (keyIndex > std::numeric_limits<uint32_t>::max()) {
+                Logger::error()
+                        << "resource key string pool exceeded max size."
+                        << std::endl;
+                return false;
+            }
+
+            for (const auto& configValue : entry->values) {
+                data[configValue.config].push_back(FlatEntry{
+                        *entry,
+                        *configValue.value,
+                        static_cast<uint32_t>(keyIndex),
+                        static_cast<uint32_t>(sourcePool.makeRef(util::utf8ToUtf16(
+                                        configValue.source.path)).getIndex()),
+                        static_cast<uint32_t>(configValue.source.line)
+                });
+            }
+        }
+
+        // Begin flattening a configuration for the current type.
+        for (const auto& entry : data) {
+            const size_t typeHeaderStart = typeBlock.size();
+            android::ResTable_type* typeHeader = typeBlock.nextBlock<android::ResTable_type>();
+            typeHeader->header.type = android::RES_TABLE_TYPE_TYPE;
+            typeHeader->header.headerSize = sizeof(*typeHeader);
+            typeHeader->id = type->typeId;
+            typeHeader->entryCount = type->entries.size();
+            typeHeader->entriesStart = typeHeader->header.headerSize
+                    + (sizeof(uint32_t) * type->entries.size());
+            typeHeader->config = entry.first;
+
+            uint32_t* indices = typeBlock.nextBlock<uint32_t>(type->entries.size());
+            memset(indices, 0xff, type->entries.size() * sizeof(uint32_t));
+
+            const size_t entryStart = typeBlock.size();
+            for (const FlatEntry& flatEntry : entry.second) {
+                assert(flatEntry.entry.entryId < type->entries.size());
+                indices[flatEntry.entry.entryId] = typeBlock.size() - entryStart;
+                if (!flattenValue(&typeBlock, flatEntry, symbolEntries)) {
+                    Logger::error()
+                            << "failed to flatten resource '"
+                            << ResourceNameRef {
+                                    table.getPackage(), type->type, flatEntry.entry.name }
+                            << "' for configuration '"
+                            << entry.first
+                            << "'."
+                            << std::endl;
+                    return false;
+                }
+            }
+
+            typeBlock.align4();
+            typeHeader->header.size = typeBlock.size() - typeHeaderStart;
+        }
+    }
+
+    const size_t beforeTable = out->size();
+    android::ResTable_header* header = out->nextBlock<android::ResTable_header>();
+    header->header.type = android::RES_TABLE_TYPE;
+    header->header.headerSize = sizeof(*header);
+    header->packageCount = 1;
+
+    SymbolTable_entry* symbolEntryData = nullptr;
+    if (!symbolEntries.empty() && mOptions.useExtendedChunks) {
+        const size_t beforeSymbolTable = out->size();
+        StringPool symbolPool;
+        SymbolTable_header* symbolHeader = out->nextBlock<SymbolTable_header>();
+        symbolHeader->header.type = RES_TABLE_SYMBOL_TABLE_TYPE;
+        symbolHeader->header.headerSize = sizeof(*symbolHeader);
+        symbolHeader->count = symbolEntries.size();
+
+        symbolEntryData = out->nextBlock<SymbolTable_entry>(symbolHeader->count);
+
+        size_t i = 0;
+        for (const auto& entry : symbolEntries) {
+            symbolEntryData[i].offset = entry.second;
+            StringPool::Ref ref = symbolPool.makeRef(
+                    entry.first.package.toString() + u":" +
+                    toString(entry.first.type).toString() + u"/" +
+                    entry.first.entry.toString());
+            symbolEntryData[i].stringIndex = ref.getIndex();
+            i++;
+        }
+
+        StringPool::flattenUtf8(out, symbolPool);
+        out->align4();
+        symbolHeader->header.size = out->size() - beforeSymbolTable;
+    }
+
+    if (sourcePool.size() > 0 && mOptions.useExtendedChunks) {
+        const size_t beforeSourcePool = out->size();
+        android::ResChunk_header* sourceHeader = out->nextBlock<android::ResChunk_header>();
+        sourceHeader->type = RES_TABLE_SOURCE_POOL_TYPE;
+        sourceHeader->headerSize = sizeof(*sourceHeader);
+        StringPool::flattenUtf8(out, sourcePool);
+        out->align4();
+        sourceHeader->size = out->size() - beforeSourcePool;
+    }
+
+    StringPool::flattenUtf8(out, table.getValueStringPool());
+
+    const size_t beforePackageIndex = out->size();
+    android::ResTable_package* package = out->nextBlock<android::ResTable_package>();
+    package->header.type = android::RES_TABLE_PACKAGE_TYPE;
+    package->header.headerSize = sizeof(*package);
+
+    if (table.getPackageId() > std::numeric_limits<uint8_t>::max()) {
+        Logger::error()
+                << "package ID 0x'"
+                << std::hex << table.getPackageId() << std::dec
+                << "' is invalid."
+                << std::endl;
+        return false;
+    }
+    package->id = table.getPackageId();
+
+    if (table.getPackage().size() >= sizeof(package->name) / sizeof(package->name[0])) {
+        Logger::error()
+                << "package name '"
+                << table.getPackage()
+                << "' is too long."
+                << std::endl;
+        return false;
+    }
+    memcpy(package->name, reinterpret_cast<const uint16_t*>(table.getPackage().data()),
+            table.getPackage().length() * sizeof(char16_t));
+    package->name[table.getPackage().length()] = 0;
+
+    package->typeStrings = package->header.headerSize;
+    StringPool::flattenUtf8(out, typePool);
+    package->keyStrings = out->size() - beforePackageIndex;
+    StringPool::flattenUtf8(out, keyPool);
+
+    if (symbolEntryData != nullptr) {
+        for (size_t i = 0; i < symbolEntries.size(); i++) {
+            symbolEntryData[i].offset += out->size() - beginning;
+        }
+    }
+
+    out->appendBuffer(std::move(typeBlock));
+
+    package->header.size = out->size() - beforePackageIndex;
+    header->header.size = out->size() - beforeTable;
+    return true;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/TableFlattener.h b/tools/aapt2/TableFlattener.h
new file mode 100644
index 0000000..0ae798c
--- /dev/null
+++ b/tools/aapt2/TableFlattener.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_TABLE_FLATTENER_H
+#define AAPT_TABLE_FLATTENER_H
+
+#include "BigBuffer.h"
+#include "ResourceTable.h"
+
+namespace aapt {
+
+struct FlatEntry;
+
+/**
+ * Flattens a ResourceTable into a binary format suitable
+ * for loading into a ResTable on the host or device.
+ */
+struct TableFlattener {
+    /**
+     * A set of options for this TableFlattener.
+     */
+    struct Options {
+        /**
+         * Specifies whether to output extended chunks, like
+         * source information and mising symbol entries. Default
+         * is true.
+         *
+         * Set this to false when emitting the final table to be used
+         * on device.
+         */
+        bool useExtendedChunks = true;
+    };
+
+    TableFlattener(Options options);
+
+    bool flatten(BigBuffer* out, const ResourceTable& table);
+
+private:
+    bool flattenValue(BigBuffer* out, const FlatEntry& flatEntry,
+                      std::vector<std::pair<ResourceNameRef, uint32_t>>& symbolEntries);
+
+    Options mOptions;
+};
+
+} // namespace aapt
+
+#endif // AAPT_TABLE_FLATTENER_H
diff --git a/tools/aapt2/Util.cpp b/tools/aapt2/Util.cpp
new file mode 100644
index 0000000..c2418eb
--- /dev/null
+++ b/tools/aapt2/Util.cpp
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BigBuffer.h"
+#include "Maybe.h"
+#include "StringPiece.h"
+#include "Util.h"
+
+#include <algorithm>
+#include <ostream>
+#include <string>
+#include <utils/Unicode.h>
+#include <vector>
+
+namespace aapt {
+namespace util {
+
+static std::vector<std::string> splitAndTransform(const StringPiece& str, char sep,
+        const std::function<char(char)>& f) {
+    std::vector<std::string> parts;
+    const StringPiece::const_iterator end = std::end(str);
+    StringPiece::const_iterator start = std::begin(str);
+    StringPiece::const_iterator current;
+    do {
+        current = std::find(start, end, sep);
+        parts.emplace_back(str.substr(start, current).toString());
+        if (f) {
+            std::string& part = parts.back();
+            std::transform(part.begin(), part.end(), part.begin(), f);
+        }
+        start = current + 1;
+    } while (current != end);
+    return parts;
+}
+
+std::vector<std::string> split(const StringPiece& str, char sep) {
+    return splitAndTransform(str, sep, nullptr);
+}
+
+std::vector<std::string> splitAndLowercase(const StringPiece& str, char sep) {
+    return splitAndTransform(str, sep, ::tolower);
+}
+
+StringPiece16 trimWhitespace(const StringPiece16& str) {
+    if (str.size() == 0 || str.data() == nullptr) {
+        return str;
+    }
+
+    const char16_t* start = str.data();
+    const char16_t* end = str.data() + str.length();
+
+    while (start != end && util::isspace16(*start)) {
+        start++;
+    }
+
+    while (end != start && util::isspace16(*(end - 1))) {
+        end--;
+    }
+
+    return StringPiece16(start, end - start);
+}
+
+StringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str,
+        const StringPiece16& allowedChars) {
+    const auto endIter = str.end();
+    for (auto iter = str.begin(); iter != endIter; ++iter) {
+        char16_t c = *iter;
+        if ((c >= u'a' && c <= u'z') ||
+                (c >= u'A' && c <= u'Z') ||
+                (c >= u'0' && c <= u'9')) {
+            continue;
+        }
+
+        bool match = false;
+        for (char16_t i : allowedChars) {
+            if (c == i) {
+                match = true;
+                break;
+            }
+        }
+
+        if (!match) {
+            return iter;
+        }
+    }
+    return endIter;
+}
+
+static Maybe<char16_t> parseUnicodeCodepoint(const char16_t** start, const char16_t* end) {
+    char16_t code = 0;
+    for (size_t i = 0; i < 4 && *start != end; i++, (*start)++) {
+        char16_t c = **start;
+        int a;
+        if (c >= '0' && c <= '9') {
+            a = c - '0';
+        } else if (c >= 'a' && c <= 'f') {
+            a = c - 'a' + 10;
+        } else if (c >= 'A' && c <= 'F') {
+            a = c - 'A' + 10;
+        } else {
+            return make_nothing<char16_t>();
+        }
+        code = (code << 4) | a;
+    }
+    return make_value(code);
+}
+
+StringBuilder& StringBuilder::append(const StringPiece16& str) {
+    if (!mError.empty()) {
+        return *this;
+    }
+
+    const char16_t* const end = str.end();
+    const char16_t* start = str.begin();
+    const char16_t* current = start;
+    while (current != end) {
+        if (*current == u'"') {
+            if (!mQuote && mTrailingSpace) {
+                // We found an opening quote, and we have
+                // trailing space, so we should append that
+                // space now.
+                if (mTrailingSpace) {
+                    // We had trailing whitespace, so
+                    // replace with a single space.
+                    if (!mStr.empty()) {
+                        mStr += u' ';
+                    }
+                    mTrailingSpace = false;
+                }
+            }
+            mQuote = !mQuote;
+            mStr.append(start, current - start);
+            start = current + 1;
+        } else if (*current == u'\'' && !mQuote) {
+            // This should be escaped.
+            mError = "unescaped apostrophe";
+            return *this;
+        } else if (*current == u'\\') {
+            // This is an escape sequence, convert to the real value.
+            if (!mQuote && mTrailingSpace) {
+                // We had trailing whitespace, so
+                // replace with a single space.
+                if (!mStr.empty()) {
+                    mStr += u' ';
+                }
+                mTrailingSpace = false;
+            }
+            mStr.append(start, current - start);
+            start = current + 1;
+
+            current++;
+            if (current != end) {
+                switch (*current) {
+                    case u't':
+                        mStr += u'\t';
+                        break;
+                    case u'n':
+                        mStr += u'\n';
+                        break;
+                    case u'#':
+                        mStr += u'#';
+                        break;
+                    case u'@':
+                        mStr += u'@';
+                        break;
+                    case u'?':
+                        mStr += u'?';
+                        break;
+                    case u'"':
+                        mStr += u'"';
+                        break;
+                    case u'\'':
+                        mStr += u'\'';
+                        break;
+                    case u'\\':
+                        mStr += u'\\';
+                        break;
+                    case u'u': {
+                        current++;
+                        Maybe<char16_t> c = parseUnicodeCodepoint(&current, end);
+                        if (!c) {
+                            mError = "invalid unicode escape sequence";
+                            return *this;
+                        }
+                        mStr += c.value();
+                        current -= 1;
+                        break;
+                    }
+
+                    default:
+                        // Ignore.
+                        break;
+                }
+                start = current + 1;
+            }
+        } else if (!mQuote) {
+            // This is not quoted text, so look for whitespace.
+            if (isspace16(*current)) {
+                // We found whitespace, see if we have seen some
+                // before.
+                if (!mTrailingSpace) {
+                    // We didn't see a previous adjacent space,
+                    // so mark that we did.
+                    mTrailingSpace = true;
+                    mStr.append(start, current - start);
+                }
+
+                // Keep skipping whitespace.
+                start = current + 1;
+            } else if (mTrailingSpace) {
+                // We saw trailing space before, so replace all
+                // that trailing space with one space.
+                if (!mStr.empty()) {
+                    mStr += u' ';
+                }
+                mTrailingSpace = false;
+            }
+        }
+        current++;
+    }
+    mStr.append(start, end - start);
+    return *this;
+}
+
+std::u16string utf8ToUtf16(const StringPiece& utf8) {
+    ssize_t utf16Length = utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(utf8.data()),
+            utf8.length());
+    if (utf16Length <= 0) {
+        return {};
+    }
+
+    std::u16string utf16;
+    utf16.resize(utf16Length);
+    utf8_to_utf16(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length(), &*utf16.begin());
+    return utf16;
+}
+
+std::string utf16ToUtf8(const StringPiece16& utf16) {
+    ssize_t utf8Length = utf16_to_utf8_length(utf16.data(), utf16.length());
+    if (utf8Length <= 0) {
+        return {};
+    }
+
+    std::string utf8;
+    utf8.resize(utf8Length);
+    utf16_to_utf8(utf16.data(), utf16.length(), &*utf8.begin());
+    return utf8;
+}
+
+bool writeAll(std::ostream& out, const BigBuffer& buffer) {
+    for (const auto& b : buffer) {
+        if (!out.write(reinterpret_cast<const char*>(b.buffer.get()), b.size)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+std::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer) {
+    std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
+    uint8_t* p = data.get();
+    for (const auto& block : buffer) {
+        memcpy(p, block.buffer.get(), block.size);
+        p += block.size;
+    }
+    return data;
+}
+
+} // namespace util
+} // namespace aapt
diff --git a/tools/aapt2/Util.h b/tools/aapt2/Util.h
new file mode 100644
index 0000000..9f9707c
--- /dev/null
+++ b/tools/aapt2/Util.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_UTIL_H
+#define AAPT_UTIL_H
+
+#include "BigBuffer.h"
+#include "StringPiece.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <functional>
+#include <memory>
+#include <ostream>
+#include <string>
+#include <vector>
+
+namespace aapt {
+namespace util {
+
+std::vector<std::string> split(const StringPiece& str, char sep);
+std::vector<std::string> splitAndLowercase(const StringPiece& str, char sep);
+
+/**
+ * Returns true if the string starts with prefix.
+ */
+template <typename T>
+bool stringStartsWith(const BasicStringPiece<T>& str, const BasicStringPiece<T>& prefix) {
+    if (str.size() < prefix.size()) {
+        return false;
+    }
+    return str.substr(0, prefix.size()) == prefix;
+}
+
+/**
+ * Returns true if the string ends with suffix.
+ */
+template <typename T>
+bool stringEndsWith(const BasicStringPiece<T>& str, const BasicStringPiece<T>& suffix) {
+    if (str.size() < suffix.size()) {
+        return false;
+    }
+    return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
+}
+
+/**
+ * Creates a new StringPiece16 that points to a substring
+ * of the original string without leading or trailing whitespace.
+ */
+StringPiece16 trimWhitespace(const StringPiece16& str);
+
+/**
+ * UTF-16 isspace(). It basically checks for lower range characters that are
+ * whitespace.
+ */
+inline bool isspace16(char16_t c) {
+    return c < 0x0080 && isspace(c);
+}
+
+/**
+ * Returns an iterator to the first character that is not alpha-numeric and that
+ * is not in the allowedChars set.
+ */
+StringPiece16::const_iterator findNonAlphaNumericAndNotInSet(const StringPiece16& str,
+        const StringPiece16& allowedChars);
+
+/**
+ * Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
+ * This will be present in C++14 and can be removed then.
+ */
+template <typename T, class... Args>
+std::unique_ptr<T> make_unique(Args&&... args) {
+    return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
+}
+
+/**
+ * Writes a set of items to the std::ostream, joining the times with the provided
+ * separator.
+ */
+template <typename Iterator>
+::std::function<::std::ostream&(::std::ostream&)> joiner(Iterator begin, Iterator end,
+        const char* sep) {
+    return [begin, end, sep](::std::ostream& out) -> ::std::ostream& {
+        for (auto iter = begin; iter != end; ++iter) {
+            if (iter != begin) {
+                out << sep;
+            }
+            out << *iter;
+        }
+        return out;
+    };
+}
+
+inline ::std::function<::std::ostream&(::std::ostream&)> formatSize(size_t size) {
+    return [size](::std::ostream& out) -> ::std::ostream& {
+        constexpr size_t K = 1024u;
+        constexpr size_t M = K * K;
+        constexpr size_t G = M * K;
+        if (size < K) {
+            out << size << "B";
+        } else if (size < M) {
+            out << (double(size) / K) << " KiB";
+        } else if (size < G) {
+            out << (double(size) / M) << " MiB";
+        } else {
+            out << (double(size) / G) << " GiB";
+        }
+        return out;
+    };
+}
+
+/**
+ * Helper method to extract a string from a StringPool.
+ */
+inline StringPiece16 getString(const android::ResStringPool& pool, size_t idx) {
+    size_t len;
+    const char16_t* str = pool.stringAt(idx, &len);
+    if (str != nullptr) {
+        return StringPiece16(str, len);
+    }
+    return StringPiece16();
+}
+
+class StringBuilder {
+public:
+    StringBuilder& append(const StringPiece16& str);
+    const std::u16string& str() const;
+    const std::string& error() const;
+    operator bool() const;
+
+private:
+    std::u16string mStr;
+    bool mQuote = false;
+    bool mTrailingSpace = false;
+    std::string mError;
+};
+
+inline const std::u16string& StringBuilder::str() const {
+    return mStr;
+}
+
+inline const std::string& StringBuilder::error() const {
+    return mError;
+}
+
+inline StringBuilder::operator bool() const {
+    return mError.empty();
+}
+
+/**
+ * Converts a UTF8 string to a UTF16 string.
+ */
+std::u16string utf8ToUtf16(const StringPiece& utf8);
+std::string utf16ToUtf8(const StringPiece16& utf8);
+
+/**
+ * Writes the entire BigBuffer to the output stream.
+ */
+bool writeAll(std::ostream& out, const BigBuffer& buffer);
+
+/*
+ * Copies the entire BigBuffer into a single buffer.
+ */
+std::unique_ptr<uint8_t[]> copy(const BigBuffer& buffer);
+
+/**
+ * A Tokenizer implemented as an iterable collection. It does not allocate
+ * any memory on the heap nor use standard containers.
+ */
+template <typename Char>
+class Tokenizer {
+public:
+    class iterator {
+    public:
+        iterator(const iterator&) = default;
+        iterator& operator=(const iterator&) = default;
+
+        iterator& operator++();
+        BasicStringPiece<Char> operator*();
+        bool operator==(const iterator& rhs) const;
+        bool operator!=(const iterator& rhs) const;
+
+    private:
+        friend class Tokenizer<Char>;
+
+        iterator(BasicStringPiece<Char> s, Char sep, BasicStringPiece<Char> tok);
+
+        BasicStringPiece<Char> str;
+        Char separator;
+        BasicStringPiece<Char> token;
+    };
+
+    Tokenizer(BasicStringPiece<Char> str, Char sep);
+    iterator begin();
+    iterator end();
+
+private:
+    const iterator mBegin;
+    const iterator mEnd;
+};
+
+template <typename Char>
+inline Tokenizer<Char> tokenize(BasicStringPiece<Char> str, Char sep) {
+    return Tokenizer<Char>(str, sep);
+}
+
+template <typename Char>
+typename Tokenizer<Char>::iterator& Tokenizer<Char>::iterator::operator++() {
+    const Char* start = token.end();
+    const Char* end = str.end();
+    if (start == end) {
+        token.assign(token.end(), 0);
+        return *this;
+    }
+
+    start += 1;
+    const Char* current = start;
+    while (current != end) {
+        if (*current == separator) {
+            token.assign(start, current - start);
+            return *this;
+        }
+        ++current;
+    }
+    token.assign(start, end - start);
+    return *this;
+}
+
+template <typename Char>
+inline BasicStringPiece<Char> Tokenizer<Char>::iterator::operator*() {
+    return token;
+}
+
+template <typename Char>
+inline bool Tokenizer<Char>::iterator::operator==(const iterator& rhs) const {
+    // We check equality here a bit differently.
+    // We need to know that the addresses are the same.
+    return token.begin() == rhs.token.begin() && token.end() == rhs.token.end();
+}
+
+template <typename Char>
+inline bool Tokenizer<Char>::iterator::operator!=(const iterator& rhs) const {
+    return !(*this == rhs);
+}
+
+template <typename Char>
+inline Tokenizer<Char>::iterator::iterator(BasicStringPiece<Char> s, Char sep,
+                                           BasicStringPiece<Char> tok) :
+        str(s), separator(sep), token(tok) {
+}
+
+template <typename Char>
+inline typename Tokenizer<Char>::iterator Tokenizer<Char>::begin() {
+    return mBegin;
+}
+
+template <typename Char>
+inline typename Tokenizer<Char>::iterator Tokenizer<Char>::end() {
+    return mEnd;
+}
+
+template <typename Char>
+inline Tokenizer<Char>::Tokenizer(BasicStringPiece<Char> str, Char sep) :
+        mBegin(++iterator(str, sep, BasicStringPiece<Char>(str.begin() - 1, 0))),
+        mEnd(str, sep, BasicStringPiece<Char>(str.end(), 0)) {
+}
+
+} // namespace util
+
+/**
+ * Stream operator for functions. Calls the function with the stream as an argument.
+ * In the aapt namespace for lookup.
+ */
+inline ::std::ostream& operator<<(::std::ostream& out,
+                                  ::std::function<::std::ostream&(::std::ostream&)> f) {
+    return f(out);
+}
+
+} // namespace aapt
+
+#endif // AAPT_UTIL_H
diff --git a/tools/aapt2/Util_test.cpp b/tools/aapt2/Util_test.cpp
new file mode 100644
index 0000000..c16f6bb
--- /dev/null
+++ b/tools/aapt2/Util_test.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "StringPiece.h"
+#include "Util.h"
+
+namespace aapt {
+
+TEST(UtilTest, TrimOnlyWhitespace) {
+    const std::u16string full = u"\n        ";
+
+    StringPiece16 trimmed = util::trimWhitespace(full);
+    EXPECT_TRUE(trimmed.empty());
+    EXPECT_EQ(0u, trimmed.size());
+}
+
+TEST(UtilTest, StringEndsWith) {
+    EXPECT_TRUE(util::stringEndsWith<char>("hello.xml", ".xml"));
+}
+
+TEST(UtilTest, StringStartsWith) {
+    EXPECT_TRUE(util::stringStartsWith<char>("hello.xml", "he"));
+}
+
+TEST(UtilTest, StringBuilderWhitespaceRemoval) {
+    EXPECT_EQ(StringPiece16(u"hey guys this is so cool"),
+            util::StringBuilder().append(u"    hey guys ")
+                                 .append(u" this is so cool ")
+                                 .str());
+
+    EXPECT_EQ(StringPiece16(u" wow,  so many \t spaces. what?"),
+            util::StringBuilder().append(u" \" wow,  so many \t ")
+                                 .append(u"spaces. \"what? ")
+                                 .str());
+
+    EXPECT_EQ(StringPiece16(u"where is the pie?"),
+            util::StringBuilder().append(u"  where \t ")
+                                 .append(u" \nis the "" pie?")
+                                 .str());
+}
+
+TEST(UtilTest, StringBuilderEscaping) {
+    EXPECT_EQ(StringPiece16(u"hey guys\n this \t is so\\ cool"),
+            util::StringBuilder().append(u"    hey guys\\n ")
+                                 .append(u" this \\t is so\\\\ cool ")
+                                 .str());
+
+    EXPECT_EQ(StringPiece16(u"@?#\\\'"),
+            util::StringBuilder().append(u"\\@\\?\\#\\\\\\'")
+                                 .str());
+}
+
+TEST(UtilTest, StringBuilderMisplacedQuote) {
+    util::StringBuilder builder{};
+    EXPECT_FALSE(builder.append(u"they're coming!"));
+}
+
+TEST(UtilTest, StringBuilderUnicodeCodes) {
+    EXPECT_EQ(StringPiece16(u"\u00AF\u0AF0 woah"),
+            util::StringBuilder().append(u"\\u00AF\\u0AF0 woah")
+                                 .str());
+
+    EXPECT_FALSE(util::StringBuilder().append(u"\\u00 yo"));
+}
+
+TEST(UtilTest, TokenizeInput) {
+    auto tokenizer = util::tokenize(StringPiece16(u"this| is|the|end"), u'|');
+    auto iter = tokenizer.begin();
+    ASSERT_EQ(*iter, StringPiece16(u"this"));
+    ++iter;
+    ASSERT_EQ(*iter, StringPiece16(u" is"));
+    ++iter;
+    ASSERT_EQ(*iter, StringPiece16(u"the"));
+    ++iter;
+    ASSERT_EQ(*iter, StringPiece16(u"end"));
+    ++iter;
+    ASSERT_EQ(tokenizer.end(), iter);
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/XliffXmlPullParser.cpp b/tools/aapt2/XliffXmlPullParser.cpp
new file mode 100644
index 0000000..f0950a3
--- /dev/null
+++ b/tools/aapt2/XliffXmlPullParser.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "XliffXmlPullParser.h"
+
+#include <string>
+
+namespace aapt {
+
+XliffXmlPullParser::XliffXmlPullParser(const std::shared_ptr<XmlPullParser>& parser) :
+        mParser(parser) {
+}
+
+XmlPullParser::Event XliffXmlPullParser::next() {
+    while (XmlPullParser::isGoodEvent(mParser->next())) {
+        Event event = mParser->getEvent();
+        if (event != Event::kStartElement && event != Event::kEndElement) {
+            break;
+        }
+
+        if (mParser->getElementNamespace() !=
+                u"urn:oasis:names:tc:xliff:document:1.2") {
+            break;
+        }
+
+        const std::u16string& name = mParser->getElementName();
+        if (name != u"bpt"
+                && name != u"ept"
+                && name != u"it"
+                && name != u"ph"
+                && name != u"g"
+                && name != u"bx"
+                && name != u"ex"
+                && name != u"x") {
+            break;
+        }
+
+        // We hit a tag that was ignored, so get the next event.
+    }
+    return mParser->getEvent();
+}
+
+XmlPullParser::Event XliffXmlPullParser::getEvent() const {
+    return mParser->getEvent();
+}
+
+const std::string& XliffXmlPullParser::getLastError() const {
+    return mParser->getLastError();
+}
+
+const std::u16string& XliffXmlPullParser::getComment() const {
+    return mParser->getComment();
+}
+
+size_t XliffXmlPullParser::getLineNumber() const {
+    return mParser->getLineNumber();
+}
+
+size_t XliffXmlPullParser::getDepth() const {
+    return mParser->getDepth();
+}
+
+const std::u16string& XliffXmlPullParser::getText() const {
+    return mParser->getText();
+}
+
+const std::u16string& XliffXmlPullParser::getNamespacePrefix() const {
+    return mParser->getNamespacePrefix();
+}
+
+const std::u16string& XliffXmlPullParser::getNamespaceUri() const {
+    return mParser->getNamespaceUri();
+}
+
+const std::u16string& XliffXmlPullParser::getElementNamespace() const {
+    return mParser->getElementNamespace();
+}
+
+const std::u16string& XliffXmlPullParser::getElementName() const {
+    return mParser->getElementName();
+}
+
+size_t XliffXmlPullParser::getAttributeCount() const {
+    return mParser->getAttributeCount();
+}
+
+XmlPullParser::const_iterator XliffXmlPullParser::beginAttributes() const {
+    return mParser->beginAttributes();
+}
+
+XmlPullParser::const_iterator XliffXmlPullParser::endAttributes() const {
+    return mParser->endAttributes();
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/XliffXmlPullParser.h b/tools/aapt2/XliffXmlPullParser.h
new file mode 100644
index 0000000..d4aa222
--- /dev/null
+++ b/tools/aapt2/XliffXmlPullParser.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_XLIFF_XML_PULL_PARSER_H
+#define AAPT_XLIFF_XML_PULL_PARSER_H
+
+#include "XmlPullParser.h"
+
+#include <memory>
+#include <string>
+
+namespace aapt {
+
+/**
+ * Strips xliff elements and provides the caller with a view of the
+ * underlying XML without xliff.
+ */
+class XliffXmlPullParser : public XmlPullParser {
+public:
+    XliffXmlPullParser(const std::shared_ptr<XmlPullParser>& parser);
+    XliffXmlPullParser(const XliffXmlPullParser& rhs) = delete;
+
+    Event getEvent() const;
+    const std::string& getLastError() const;
+    Event next();
+
+    const std::u16string& getComment() const;
+    size_t getLineNumber() const;
+    size_t getDepth() const;
+
+    const std::u16string& getText() const;
+
+    const std::u16string& getNamespacePrefix() const;
+    const std::u16string& getNamespaceUri() const;
+
+    const std::u16string& getElementNamespace() const;
+    const std::u16string& getElementName() const;
+
+    const_iterator beginAttributes() const;
+    const_iterator endAttributes() const;
+    size_t getAttributeCount() const;
+
+private:
+    std::shared_ptr<XmlPullParser> mParser;
+};
+
+} // namespace aapt
+
+#endif // AAPT_XLIFF_XML_PULL_PARSER_H
diff --git a/tools/aapt2/XliffXmlPullParser_test.cpp b/tools/aapt2/XliffXmlPullParser_test.cpp
new file mode 100644
index 0000000..f9030724
--- /dev/null
+++ b/tools/aapt2/XliffXmlPullParser_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SourceXmlPullParser.h"
+#include "XliffXmlPullParser.h"
+
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+namespace aapt {
+
+TEST(XliffXmlPullParserTest, IgnoreXliffTags) {
+    std::stringstream input;
+    input << "<?xml version=\"1.0\" encoding=\"utf-8\"?>" << std::endl
+          << "<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">" << std::endl
+          << "<string name=\"foo\">"
+          << "Hey <xliff:g><xliff:it>there</xliff:it></xliff:g> world</string>" << std::endl
+          << "</resources>" << std::endl;
+    std::shared_ptr<XmlPullParser> sourceParser = std::make_shared<SourceXmlPullParser>(input);
+    XliffXmlPullParser parser(sourceParser);
+    EXPECT_EQ(XmlPullParser::Event::kStartDocument, parser.getEvent());
+
+    EXPECT_EQ(XmlPullParser::Event::kStartNamespace, parser.next());
+    EXPECT_EQ(parser.getNamespaceUri(), u"urn:oasis:names:tc:xliff:document:1.2");
+    EXPECT_EQ(parser.getNamespacePrefix(), u"xliff");
+
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, parser.next());
+    EXPECT_EQ(parser.getElementNamespace(), u"");
+    EXPECT_EQ(parser.getElementName(), u"resources");
+    EXPECT_EQ(XmlPullParser::Event::kText, parser.next()); // Account for newline/whitespace.
+
+    EXPECT_EQ(XmlPullParser::Event::kStartElement, parser.next());
+    EXPECT_EQ(parser.getElementNamespace(), u"");
+    EXPECT_EQ(parser.getElementName(), u"string");
+
+    EXPECT_EQ(XmlPullParser::Event::kText, parser.next());
+    EXPECT_EQ(parser.getText(), u"Hey ");
+
+    EXPECT_EQ(XmlPullParser::Event::kText, parser.next());
+    EXPECT_EQ(parser.getText(), u"there");
+
+    EXPECT_EQ(XmlPullParser::Event::kText, parser.next());
+    EXPECT_EQ(parser.getText(), u" world");
+
+    EXPECT_EQ(XmlPullParser::Event::kEndElement, parser.next());
+    EXPECT_EQ(parser.getElementNamespace(), u"");
+    EXPECT_EQ(parser.getElementName(), u"string");
+    EXPECT_EQ(XmlPullParser::Event::kText, parser.next()); // Account for newline/whitespace.
+
+    EXPECT_EQ(XmlPullParser::Event::kEndElement, parser.next());
+    EXPECT_EQ(parser.getElementNamespace(), u"");
+    EXPECT_EQ(parser.getElementName(), u"resources");
+
+    EXPECT_EQ(XmlPullParser::Event::kEndNamespace, parser.next());
+    EXPECT_EQ(parser.getNamespacePrefix(), u"xliff");
+    EXPECT_EQ(parser.getNamespaceUri(), u"urn:oasis:names:tc:xliff:document:1.2");
+
+    EXPECT_EQ(XmlPullParser::Event::kEndDocument, parser.next());
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/XmlFlattener.cpp b/tools/aapt2/XmlFlattener.cpp
new file mode 100644
index 0000000..b6ca6d5
--- /dev/null
+++ b/tools/aapt2/XmlFlattener.cpp
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "BigBuffer.h"
+#include "Logger.h"
+#include "Maybe.h"
+#include "Resolver.h"
+#include "Resource.h"
+#include "ResourceParser.h"
+#include "ResourceValues.h"
+#include "SdkConstants.h"
+#include "Source.h"
+#include "StringPool.h"
+#include "Util.h"
+#include "XmlFlattener.h"
+
+#include <androidfw/ResourceTypes.h>
+#include <limits>
+#include <map>
+#include <string>
+#include <vector>
+
+namespace aapt {
+
+struct AttributeValueFlattener : ValueVisitor {
+    struct Args : ValueVisitorArgs {
+        Args(std::shared_ptr<Resolver> r, SourceLogger& s, android::Res_value& oV,
+                std::shared_ptr<XmlPullParser> p, bool& e, StringPool::Ref& rV,
+                std::vector<std::pair<StringPool::Ref, android::ResStringPool_ref*>>& sR) :
+                resolver(r), logger(s), outValue(oV), parser(p), error(e), rawValue(rV),
+                stringRefs(sR) {
+        }
+
+        std::shared_ptr<Resolver> resolver;
+        SourceLogger& logger;
+        android::Res_value& outValue;
+        std::shared_ptr<XmlPullParser> parser;
+        bool& error;
+        StringPool::Ref& rawValue;
+        std::vector<std::pair<StringPool::Ref, android::ResStringPool_ref*>>& stringRefs;
+    };
+
+    void visit(Reference& reference, ValueVisitorArgs& a) override {
+        Args& args = static_cast<Args&>(a);
+
+        Maybe<ResourceId> result = args.resolver->findId(reference.name);
+        if (!result || !result.value().isValid()) {
+            args.logger.error(args.parser->getLineNumber())
+                    << "unresolved reference '"
+                    << reference.name
+                    << "'."
+                    << std::endl;
+            args.error = true;
+        } else {
+            reference.id = result.value();
+            reference.flatten(args.outValue);
+        }
+    }
+
+    void visit(String& string, ValueVisitorArgs& a) override {
+        Args& args = static_cast<Args&>(a);
+
+        args.outValue.dataType = android::Res_value::TYPE_STRING;
+        args.stringRefs.emplace_back(args.rawValue,
+                reinterpret_cast<android::ResStringPool_ref*>(&args.outValue.data));
+    }
+
+    void visitItem(Item& item, ValueVisitorArgs& a) override {
+        Args& args = static_cast<Args&>(a);
+        item.flatten(args.outValue);
+    }
+};
+
+struct XmlAttribute {
+    uint32_t resourceId;
+    const XmlPullParser::Attribute* xmlAttr;
+    const Attribute* attr;
+    StringPool::Ref nameRef;
+};
+
+static bool lessAttributeId(const XmlAttribute& a, uint32_t id) {
+    return a.resourceId < id;
+}
+
+XmlFlattener::XmlFlattener(const std::shared_ptr<Resolver>& resolver) : mResolver(resolver) {
+}
+
+/**
+ * Reads events from the parser and writes to a BigBuffer. The binary XML file
+ * expects the StringPool to appear first, but we haven't collected the strings yet. We
+ * write to a temporary BigBuffer while parsing the input, adding strings we encounter
+ * to the StringPool. At the end, we write the StringPool to the given BigBuffer and
+ * then move the data from the temporary BigBuffer into the given one. This incurs no
+ * copies as the given BigBuffer simply takes ownership of the data.
+ */
+Maybe<size_t> XmlFlattener::flatten(const Source& source,
+                                    const std::shared_ptr<XmlPullParser>& parser,
+                                    BigBuffer* outBuffer, Options options) {
+    SourceLogger logger(source);
+    StringPool pool;
+    bool error = false;
+
+    size_t smallestStrippedAttributeSdk = std::numeric_limits<size_t>::max();
+
+    // Attribute names are stored without packages, but we use
+    // their StringPool index to lookup their resource IDs.
+    // This will cause collisions, so we can't dedupe
+    // attribute names from different packages. We use separate
+    // pools that we later combine.
+    std::map<std::u16string, StringPool> packagePools;
+
+    // Attribute resource IDs are stored in the same order
+    // as the attribute names appear in the StringPool.
+    // Since the StringPool contains more than just attribute
+    // names, to maintain a tight packing of resource IDs,
+    // we must ensure that attribute names appear first
+    // in our StringPool. For this, we assign a low priority
+    // (0xffffffff) to non-attribute strings. Attribute
+    // names will be stored along with a priority equal
+    // to their resource ID so that they are ordered.
+    StringPool::Context lowPriority { 0xffffffffu };
+
+    // Once we sort the StringPool, we can assign the updated indices
+    // to the correct data locations.
+    std::vector<std::pair<StringPool::Ref, android::ResStringPool_ref*>> stringRefs;
+
+    // Since we don't know the size of the final StringPool, we write to this
+    // temporary BigBuffer, which we will append to outBuffer later.
+    BigBuffer out(1024);
+    while (XmlPullParser::isGoodEvent(parser->next())) {
+        XmlPullParser::Event event = parser->getEvent();
+        switch (event) {
+            case XmlPullParser::Event::kStartNamespace:
+            case XmlPullParser::Event::kEndNamespace: {
+                const size_t startIndex = out.size();
+                android::ResXMLTree_node* node = out.nextBlock<android::ResXMLTree_node>();
+                if (event == XmlPullParser::Event::kStartNamespace) {
+                    node->header.type = android::RES_XML_START_NAMESPACE_TYPE;
+                } else {
+                    node->header.type = android::RES_XML_END_NAMESPACE_TYPE;
+                }
+
+                node->header.headerSize = sizeof(*node);
+                node->lineNumber = parser->getLineNumber();
+                node->comment.index = -1;
+
+                android::ResXMLTree_namespaceExt* ns =
+                        out.nextBlock<android::ResXMLTree_namespaceExt>();
+                stringRefs.emplace_back(
+                        pool.makeRef(parser->getNamespacePrefix(), lowPriority), &ns->prefix);
+                stringRefs.emplace_back(
+                        pool.makeRef(parser->getNamespaceUri(), lowPriority), &ns->uri);
+
+                out.align4();
+                node->header.size = out.size() - startIndex;
+                break;
+            }
+
+            case XmlPullParser::Event::kStartElement: {
+                const size_t startIndex = out.size();
+                android::ResXMLTree_node* node = out.nextBlock<android::ResXMLTree_node>();
+                node->header.type = android::RES_XML_START_ELEMENT_TYPE;
+                node->header.headerSize = sizeof(*node);
+                node->lineNumber = parser->getLineNumber();
+                node->comment.index = -1;
+
+                android::ResXMLTree_attrExt* elem = out.nextBlock<android::ResXMLTree_attrExt>();
+                stringRefs.emplace_back(
+                        pool.makeRef(parser->getElementNamespace(), lowPriority), &elem->ns);
+                stringRefs.emplace_back(
+                        pool.makeRef(parser->getElementName(), lowPriority), &elem->name);
+                elem->attributeStart = sizeof(*elem);
+                elem->attributeSize = sizeof(android::ResXMLTree_attribute);
+
+                // The resource system expects attributes to be sorted by resource ID.
+                std::vector<XmlAttribute> sortedAttributes;
+                uint32_t nextAttributeId = 0;
+                const auto endAttrIter = parser->endAttributes();
+                for (auto attrIter = parser->beginAttributes();
+                     attrIter != endAttrIter;
+                     ++attrIter) {
+                    uint32_t id;
+                    StringPool::Ref nameRef;
+                    const Attribute* attr = nullptr;
+                    if (attrIter->namespaceUri.empty()) {
+                        // Attributes that have no resource ID (because they don't belong to a
+                        // package) should appear after those that do have resource IDs. Assign
+                        // them some/ integer value that will appear after.
+                        id = 0x80000000u | nextAttributeId++;
+                        nameRef = pool.makeRef(attrIter->name, StringPool::Context{ id });
+                    } else {
+                        StringPiece16 package;
+                        if (attrIter->namespaceUri == u"http://schemas.android.com/apk/res-auto") {
+                            package = mResolver->getDefaultPackage();
+                        } else {
+                            // TODO(adamlesinski): Extract package from namespace.
+                            // The package name appears like so:
+                            // http://schemas.android.com/apk/res/<package name>
+                            package = u"android";
+                        }
+
+                        // Find the Attribute object via our Resolver.
+                        ResourceName attrName = {
+                                package.toString(), ResourceType::kAttr, attrIter->name };
+                        Maybe<Resolver::Entry> result = mResolver->findAttribute(attrName);
+                        if (!result || !result.value().id.isValid()) {
+                            logger.error(parser->getLineNumber())
+                                    << "unresolved attribute '"
+                                    << attrName
+                                    << "'."
+                                    << std::endl;
+                            error = true;
+                            continue;
+                        }
+
+                        if (!result.value().attr) {
+                            logger.error(parser->getLineNumber())
+                                    << "not a valid attribute '"
+                                    << attrName
+                                    << "'."
+                                    << std::endl;
+                            error = true;
+                            continue;
+                        }
+
+                        if (options.maxSdkAttribute && package == u"android") {
+                            size_t sdkVersion = findAttributeSdkLevel(attrIter->name);
+                            if (sdkVersion > options.maxSdkAttribute.value()) {
+                                // We will silently omit this attribute
+                                smallestStrippedAttributeSdk =
+                                        std::min(smallestStrippedAttributeSdk, sdkVersion);
+                                continue;
+                            }
+                        }
+
+                        id = result.value().id.id;
+                        attr = result.value().attr;
+
+                        // Put the attribute name into a package specific pool, since we don't
+                        // want to collapse names from different packages.
+                        nameRef = packagePools[package.toString()].makeRef(
+                                attrIter->name, StringPool::Context{ id });
+                    }
+
+                    // Insert the attribute into the sorted vector.
+                    auto iter = std::lower_bound(sortedAttributes.begin(), sortedAttributes.end(),
+                                                 id, lessAttributeId);
+                    sortedAttributes.insert(iter, XmlAttribute{ id, &*attrIter, attr, nameRef });
+                }
+
+                if (error) {
+                    break;
+                }
+
+                // Now that we have filtered out some attributes, get the final count.
+                elem->attributeCount = sortedAttributes.size();
+
+                // Flatten the sorted attributes.
+                for (auto entry : sortedAttributes) {
+                    android::ResXMLTree_attribute* attr =
+                            out.nextBlock<android::ResXMLTree_attribute>();
+                    stringRefs.emplace_back(
+                            pool.makeRef(entry.xmlAttr->namespaceUri, lowPriority), &attr->ns);
+                    StringPool::Ref rawValueRef = pool.makeRef(entry.xmlAttr->value, lowPriority);
+                    stringRefs.emplace_back(rawValueRef, &attr->rawValue);
+                    stringRefs.emplace_back(entry.nameRef, &attr->name);
+
+                    if (entry.attr) {
+                        std::unique_ptr<Item> value = ResourceParser::parseItemForAttribute(
+                                entry.xmlAttr->value, *entry.attr, mResolver->getDefaultPackage());
+                        if (value) {
+                            AttributeValueFlattener flattener;
+                            value->accept(flattener, AttributeValueFlattener::Args{
+                                    mResolver,
+                                    logger,
+                                    attr->typedValue,
+                                    parser,
+                                    error,
+                                    rawValueRef,
+                                    stringRefs
+                            });
+                        } else if (!(entry.attr->typeMask & android::ResTable_map::TYPE_STRING)) {
+                            logger.error(parser->getLineNumber())
+                                    << "'"
+                                    << *rawValueRef
+                                    << "' is not compatible with attribute "
+                                    << *entry.attr
+                                    << "."
+                                    << std::endl;
+                            error = true;
+                        } else {
+                            attr->typedValue.dataType = android::Res_value::TYPE_STRING;
+                            stringRefs.emplace_back(rawValueRef,
+                                    reinterpret_cast<android::ResStringPool_ref*>(
+                                            &attr->typedValue.data));
+                        }
+                    } else {
+                        attr->typedValue.dataType = android::Res_value::TYPE_STRING;
+                        stringRefs.emplace_back(rawValueRef,
+                                reinterpret_cast<android::ResStringPool_ref*>(
+                                        &attr->typedValue.data));
+                    }
+                    attr->typedValue.size = sizeof(attr->typedValue);
+                }
+
+                out.align4();
+                node->header.size = out.size() - startIndex;
+                break;
+            }
+
+            case XmlPullParser::Event::kEndElement: {
+                const size_t startIndex = out.size();
+                android::ResXMLTree_node* node = out.nextBlock<android::ResXMLTree_node>();
+                node->header.type = android::RES_XML_END_ELEMENT_TYPE;
+                node->header.headerSize = sizeof(*node);
+                node->lineNumber = parser->getLineNumber();
+                node->comment.index = -1;
+
+                android::ResXMLTree_endElementExt* elem =
+                        out.nextBlock<android::ResXMLTree_endElementExt>();
+                stringRefs.emplace_back(
+                        pool.makeRef(parser->getElementNamespace(), lowPriority), &elem->ns);
+                stringRefs.emplace_back(
+                        pool.makeRef(parser->getElementName(), lowPriority), &elem->name);
+
+                out.align4();
+                node->header.size = out.size() - startIndex;
+                break;
+            }
+
+            case XmlPullParser::Event::kText: {
+                StringPiece16 text = util::trimWhitespace(parser->getText());
+                if (text.empty()) {
+                    break;
+                }
+
+                const size_t startIndex = out.size();
+                android::ResXMLTree_node* node = out.nextBlock<android::ResXMLTree_node>();
+                node->header.type = android::RES_XML_CDATA_TYPE;
+                node->header.headerSize = sizeof(*node);
+                node->lineNumber = parser->getLineNumber();
+                node->comment.index = -1;
+
+                android::ResXMLTree_cdataExt* elem = out.nextBlock<android::ResXMLTree_cdataExt>();
+                stringRefs.emplace_back(pool.makeRef(text, lowPriority), &elem->data);
+
+                out.align4();
+                node->header.size = out.size() - startIndex;
+                break;
+            }
+
+            default:
+                break;
+        }
+
+    }
+    out.align4();
+
+    if (error) {
+        return {};
+    }
+
+    if (parser->getEvent() == XmlPullParser::Event::kBadDocument) {
+        logger.error(parser->getLineNumber())
+                << parser->getLastError()
+                << std::endl;
+        return {};
+    }
+
+    // Merge the package pools into the main pool.
+    for (auto& packagePoolEntry : packagePools) {
+        pool.merge(std::move(packagePoolEntry.second));
+    }
+
+    // Sort so that attribute resource IDs show up first.
+    pool.sort([](const StringPool::Entry& a, const StringPool::Entry& b) -> bool {
+        return a.context.priority < b.context.priority;
+    });
+
+    // Now we flatten the string pool references into the correct places.
+    for (const auto& refEntry : stringRefs) {
+        refEntry.second->index = refEntry.first.getIndex();
+    }
+
+    // Write the XML header.
+    const size_t beforeXmlTreeIndex = outBuffer->size();
+    android::ResXMLTree_header* header = outBuffer->nextBlock<android::ResXMLTree_header>();
+    header->header.type = android::RES_XML_TYPE;
+    header->header.headerSize = sizeof(*header);
+
+    // Write the array of resource IDs, indexed by StringPool order.
+    const size_t beforeResIdMapIndex = outBuffer->size();
+    android::ResChunk_header* resIdMapChunk = outBuffer->nextBlock<android::ResChunk_header>();
+    resIdMapChunk->type = android::RES_XML_RESOURCE_MAP_TYPE;
+    resIdMapChunk->headerSize = sizeof(*resIdMapChunk);
+    for (const auto& str : pool) {
+        ResourceId id { str->context.priority };
+        if (!id.isValid()) {
+            // When we see the first non-resource ID,
+            // we're done.
+            break;
+        }
+
+        uint32_t* flatId = outBuffer->nextBlock<uint32_t>();
+        *flatId = id.id;
+    }
+    resIdMapChunk->size = outBuffer->size() - beforeResIdMapIndex;
+
+    // Flatten the StringPool.
+    StringPool::flattenUtf8(outBuffer, pool);
+
+    // Move the temporary BigBuffer into outBuffer->
+    outBuffer->appendBuffer(std::move(out));
+
+    header->header.size = outBuffer->size() - beforeXmlTreeIndex;
+
+    if (smallestStrippedAttributeSdk == std::numeric_limits<size_t>::max()) {
+        // Nothing was stripped
+        return 0u;
+    }
+    return smallestStrippedAttributeSdk;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/XmlFlattener.h b/tools/aapt2/XmlFlattener.h
new file mode 100644
index 0000000..abf64ab
--- /dev/null
+++ b/tools/aapt2/XmlFlattener.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_XML_FLATTENER_H
+#define AAPT_XML_FLATTENER_H
+
+#include "BigBuffer.h"
+#include "Maybe.h"
+#include "Resolver.h"
+#include "Source.h"
+#include "XmlPullParser.h"
+
+namespace aapt {
+
+/**
+ * Flattens an XML file into a binary representation parseable by
+ * the Android resource system. References to resources are checked
+ * and string values are transformed to typed data where possible.
+ */
+class XmlFlattener {
+public:
+    struct Options {
+        /**
+         * If set, tells the XmlFlattener to strip out
+         * attributes that have been introduced after
+         * max SDK.
+         */
+        Maybe<size_t> maxSdkAttribute;
+    };
+
+    /**
+     * Creates a flattener with a Resolver to resolve references
+     * and attributes.
+     */
+    XmlFlattener(const std::shared_ptr<Resolver>& resolver);
+
+    XmlFlattener(const XmlFlattener&) = delete; // Not copyable.
+
+    /**
+     * Flatten an XML file, reading from the XML parser and writing to the
+     * BigBuffer. The source object is mainly for logging errors. If the
+     * function succeeds, returns the smallest SDK version of an attribute that
+     * was stripped out. If no attributes were stripped out, the return value
+     * is 0.
+     */
+    Maybe<size_t> flatten(const Source& source, const std::shared_ptr<XmlPullParser>& parser,
+                          BigBuffer* outBuffer, Options options);
+
+private:
+    std::shared_ptr<Resolver> mResolver;
+};
+
+} // namespace aapt
+
+#endif // AAPT_XML_FLATTENER_H
diff --git a/tools/aapt2/XmlFlattener_test.cpp b/tools/aapt2/XmlFlattener_test.cpp
new file mode 100644
index 0000000..6e24847
--- /dev/null
+++ b/tools/aapt2/XmlFlattener_test.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Resolver.h"
+#include "ResourceTable.h"
+#include "ResourceValues.h"
+#include "SourceXmlPullParser.h"
+#include "Util.h"
+#include "XmlFlattener.h"
+
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <gtest/gtest.h>
+#include <sstream>
+#include <string>
+
+using namespace android;
+
+namespace aapt {
+
+constexpr const char* kXmlPreamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+
+class XmlFlattenerTest : public ::testing::Test {
+public:
+    virtual void SetUp() override {
+        std::shared_ptr<ResourceTable> table = std::make_shared<ResourceTable>();
+        table->setPackage(u"android");
+        table->setPackageId(0x01);
+
+        table->addResource(ResourceName{ {}, ResourceType::kAttr, u"id" },
+                           ResourceId{ 0x01010000 }, {}, {},
+                           util::make_unique<Attribute>(false, ResTable_map::TYPE_ANY));
+
+        table->addResource(ResourceName{ {}, ResourceType::kId, u"test" },
+                           ResourceId{ 0x01020000 }, {}, {}, util::make_unique<Id>());
+
+        mFlattener = std::make_shared<XmlFlattener>(
+                std::make_shared<Resolver>(table, std::make_shared<AssetManager>()));
+    }
+
+    ::testing::AssertionResult testFlatten(std::istream& in, ResXMLTree* outTree) {
+        std::stringstream input(kXmlPreamble);
+        input << in.rdbuf() << std::endl;
+        std::shared_ptr<XmlPullParser> xmlParser = std::make_shared<SourceXmlPullParser>(input);
+        BigBuffer outBuffer(1024);
+        if (!mFlattener->flatten(Source{ "test" }, xmlParser, &outBuffer, {})) {
+            return ::testing::AssertionFailure();
+        }
+
+        std::unique_ptr<uint8_t[]> data = util::copy(outBuffer);
+        if (outTree->setTo(data.get(), outBuffer.size(), true) != NO_ERROR) {
+            return ::testing::AssertionFailure();
+        }
+        return ::testing::AssertionSuccess();
+    }
+
+    std::shared_ptr<XmlFlattener> mFlattener;
+};
+
+TEST_F(XmlFlattenerTest, ParseSimpleView) {
+    std::stringstream input;
+    input << "<View xmlns:android=\"http://schemas.android.com/apk/res/android\"" << std::endl
+          << "      android:id=\"@id/test\">" << std::endl
+          << "</View>" << std::endl;
+
+    ResXMLTree tree;
+    ASSERT_TRUE(testFlatten(input, &tree));
+
+    while (tree.next() != ResXMLTree::END_DOCUMENT) {
+        ASSERT_NE(tree.getEventType(), ResXMLTree::BAD_DOCUMENT);
+    }
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/XmlPullParser.h b/tools/aapt2/XmlPullParser.h
new file mode 100644
index 0000000..753405c
--- /dev/null
+++ b/tools/aapt2/XmlPullParser.h
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AAPT_XML_PULL_PARSER_H
+#define AAPT_XML_PULL_PARSER_H
+
+#include <algorithm>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "StringPiece.h"
+
+namespace aapt {
+
+class XmlPullParser {
+public:
+    enum class Event {
+        kBadDocument,
+        kStartDocument,
+        kEndDocument,
+
+        kStartNamespace,
+        kEndNamespace,
+        kStartElement,
+        kEndElement,
+        kText,
+        kComment,
+    };
+
+    static void skipCurrentElement(XmlPullParser* parser);
+    static bool isGoodEvent(Event event);
+
+    virtual ~XmlPullParser() {}
+
+    /**
+     * Returns the current event that is being processed.
+     */
+    virtual Event getEvent() const = 0;
+
+    virtual const std::string& getLastError() const = 0;
+
+    /**
+     * Note, unlike XmlPullParser, the first call to next() will return
+     * StartElement of the first element.
+     */
+    virtual Event next() = 0;
+
+    //
+    // These are available for all nodes.
+    //
+
+    virtual const std::u16string& getComment() const = 0;
+    virtual size_t getLineNumber() const = 0;
+    virtual size_t getDepth() const = 0;
+
+    /**
+     * Returns the character data for a Text event.
+     */
+    virtual const std::u16string& getText() const = 0;
+
+    /**
+     * Namespace prefix is available for StartNamespace and EndNamespace.
+     */
+    virtual const std::u16string& getNamespacePrefix() const = 0;
+
+    /**
+     * Namespace URI is available for StartNamespace.
+     */
+    virtual const std::u16string& getNamespaceUri() const = 0;
+
+    //
+    // These are available for StartElement and EndElement.
+    //
+
+    virtual const std::u16string& getElementNamespace() const = 0;
+    virtual const std::u16string& getElementName() const = 0;
+
+    //
+    // Remaining methods are for retrieving information about attributes
+    // associated with a StartElement.
+    //
+    // Attributes must be in sorted order (according to the less than operator
+    // of struct Attribute).
+    //
+
+    struct Attribute {
+        std::u16string namespaceUri;
+        std::u16string name;
+        std::u16string value;
+
+        int compare(const Attribute& rhs) const;
+        bool operator<(const Attribute& rhs) const;
+        bool operator==(const Attribute& rhs) const;
+        bool operator!=(const Attribute& rhs) const;
+    };
+
+    using const_iterator = std::vector<Attribute>::const_iterator;
+
+    virtual const_iterator beginAttributes() const = 0;
+    virtual const_iterator endAttributes() const = 0;
+    virtual size_t getAttributeCount() const = 0;
+    const_iterator findAttribute(StringPiece16 namespaceUri, StringPiece16 name) const;
+};
+
+//
+// Implementation
+//
+
+inline ::std::ostream& operator<<(::std::ostream& out, XmlPullParser::Event event) {
+    switch (event) {
+        case XmlPullParser::Event::kBadDocument: return out << "BadDocument";
+        case XmlPullParser::Event::kStartDocument: return out << "StartDocument";
+        case XmlPullParser::Event::kEndDocument: return out << "EndDocument";
+        case XmlPullParser::Event::kStartNamespace: return out << "StartNamespace";
+        case XmlPullParser::Event::kEndNamespace: return out << "EndNamespace";
+        case XmlPullParser::Event::kStartElement: return out << "StartElement";
+        case XmlPullParser::Event::kEndElement: return out << "EndElement";
+        case XmlPullParser::Event::kText: return out << "Text";
+        case XmlPullParser::Event::kComment: return out << "Comment";
+    }
+    return out;
+}
+
+inline void XmlPullParser::skipCurrentElement(XmlPullParser* parser) {
+    int depth = 1;
+    while (depth > 0) {
+        switch (parser->next()) {
+            case Event::kEndDocument:
+            case Event::kBadDocument:
+                return;
+            case Event::kStartElement:
+                depth++;
+                break;
+            case Event::kEndElement:
+                depth--;
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+inline bool XmlPullParser::isGoodEvent(XmlPullParser::Event event) {
+    return event != Event::kBadDocument && event != Event::kEndDocument;
+}
+
+inline int XmlPullParser::Attribute::compare(const Attribute& rhs) const {
+    int cmp = namespaceUri.compare(rhs.namespaceUri);
+    if (cmp != 0) return cmp;
+    return name.compare(rhs.name);
+}
+
+inline bool XmlPullParser::Attribute::operator<(const Attribute& rhs) const {
+    return compare(rhs) < 0;
+}
+
+inline bool XmlPullParser::Attribute::operator==(const Attribute& rhs) const {
+    return compare(rhs) == 0;
+}
+
+inline bool XmlPullParser::Attribute::operator!=(const Attribute& rhs) const {
+    return compare(rhs) != 0;
+}
+
+inline XmlPullParser::const_iterator XmlPullParser::findAttribute(StringPiece16 namespaceUri,
+                                                                  StringPiece16 name) const {
+    const auto endIter = endAttributes();
+    const auto iter = std::lower_bound(beginAttributes(), endIter,
+            std::pair<StringPiece16, StringPiece16>(namespaceUri, name),
+            [](const Attribute& attr, const std::pair<StringPiece16, StringPiece16>& rhs) -> bool {
+                int cmp = attr.namespaceUri.compare(0, attr.namespaceUri.size(),
+                        rhs.first.data(), rhs.first.size());
+                if (cmp < 0) return true;
+                if (cmp > 0) return false;
+                cmp = attr.name.compare(0, attr.name.size(), rhs.second.data(), rhs.second.size());
+                if (cmp < 0) return true;
+                return false;
+            }
+    );
+
+    if (iter != endIter && namespaceUri == iter->namespaceUri && name == iter->name) {
+        return iter;
+    }
+    return endIter;
+}
+
+} // namespace aapt
+
+#endif // AAPT_XML_PULL_PARSER_H
diff --git a/tools/aapt2/data/AndroidManifest.xml b/tools/aapt2/data/AndroidManifest.xml
new file mode 100644
index 0000000..c017a0d
--- /dev/null
+++ b/tools/aapt2/data/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.app">
+    <application>
+    </application>
+</manifest>
diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile
new file mode 100644
index 0000000..f296dc1
--- /dev/null
+++ b/tools/aapt2/data/Makefile
@@ -0,0 +1,108 @@
+##
+# Environment dependent variables
+##
+
+SHELL := /bin/bash
+AAPT := aapt2
+ZIP := zip -n .arsc:.png:AndroidManifest.xml
+ZIPALIGN := zipalign 4
+FRAMEWORK := ../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
+
+##
+# Project depenedent variables
+##
+
+LOCAL_PACKAGE := com.android.app
+LOCAL_RESOURCE_DIR := res
+LOCAL_OUT := out
+LOCAL_GEN := out/gen
+
+##
+# AAPT2 custom rules.
+##
+
+PRIVATE_ARSC := $(LOCAL_OUT)/resources.arsc
+PRIVATE_APK_UNALIGNED := $(LOCAL_OUT)/package-unaligned.apk
+PRIVATE_APK_ALIGNED := $(LOCAL_OUT)/package.apk
+
+# Eg: framework.apk, etc.
+PRIVATE_LIBS := $(FRAMEWORK)
+$(info PRIVATE_LIBS = $(PRIVATE_LIBS))
+
+# Eg: gen/com/android/app/R.java
+PRIVATE_R_JAVA := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
+$(info PRIVATE_R_JAVA = $(PRIVATE_R_JAVA))
+
+# Eg: res/drawable/icon.png, res/values/styles.xml
+PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
+$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
+
+# Eg: drawable, values, layouts
+PRIVATE_RESOURCE_TYPES := \
+	$(patsubst $(LOCAL_RESOURCE_DIR)/%/,%,$(sort $(dir $(PRIVATE_RESOURCES))))
+$(info PRIVATE_RESOURCE_TYPES = $(PRIVATE_RESOURCE_TYPES))
+
+# Eg: drawable, drawable-xhdpi, layout
+PRIVATE_NON_VALUE_RESOURCE_TYPES := $(filter-out values%,$(PRIVATE_RESOURCE_TYPES))
+$(info PRIVATE_NON_VALUE_RESOURCE_TYPES = $(PRIVATE_NON_VALUE_RESOURCE_TYPES))
+
+# Eg: out/values-v4.table, out/drawable-xhdpi.table
+PRIVATE_INTERMEDIATE_TABLES := $(patsubst %,$(LOCAL_OUT)/%.table,$(PRIVATE_RESOURCE_TYPES))
+$(info PRIVATE_INTERMEDIATE_TABLES = $(PRIVATE_INTERMEDIATE_TABLES))
+
+# Eg: out/res/layout/main.xml, out/res/drawable/icon.png
+PRIVATE_INTERMEDIATE_FILES := $(patsubst $(LOCAL_RESOURCE_DIR)/%,$(LOCAL_OUT)/res/%,$(filter-out $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES)))
+$(info PRIVATE_INTERMEDIATE_FILES = $(PRIVATE_INTERMEDIATE_FILES))
+
+# Generates rules for collect phase.
+# $1: Resource type (values-v4)
+# returns: out/values-v4.table: res/values-v4/styles.xml res/values-v4/colors.xml
+define make-collect-rule
+$(LOCAL_OUT)/$1.table: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES))
+	$(AAPT) collect --package $(LOCAL_PACKAGE) -o $$@ $$^
+endef
+
+# Collect: out/values-v4.table <- res/values-v4/styles.xml res/values-v4/colors.xml
+$(foreach d,$(PRIVATE_RESOURCE_TYPES),$(eval $(call make-collect-rule,$d)))
+
+# Link: out/resources.arsc <- out/values-v4.table out/drawable-v4.table
+$(PRIVATE_ARSC): $(PRIVATE_INTERMEDIATE_TABLES) $(PRIVATE_LIBS)
+	$(AAPT) link --package $(LOCAL_PACKAGE) $(addprefix -I ,$(PRIVATE_LIBS)) --java $(LOCAL_GEN) -o $@ $(PRIVATE_INTERMEDIATE_TABLES)
+
+# Compile Manifest: out/AndroidManifest.xml <- AndroidManifest.xml out/resources.arsc
+$(LOCAL_OUT)/AndroidManifest.xml: AndroidManifest.xml $(PRIVATE_ARSC) $(PRIVATE_LIBS)
+	$(AAPT) manifest -I $(PRIVATE_ARSC) $(addprefix -I ,$(PRIVATE_LIBS)) -o $(LOCAL_OUT) AndroidManifest.xml
+
+# Generates rules for compile phase.
+# $1: resource file (res/drawable/icon.png)
+# returns: out/res/drawable/icon.png: res/drawable/icon.png out/resources.arsc
+define make-compile-rule
+$1: $(patsubst $(LOCAL_OUT)/res/%,$(LOCAL_RESOURCE_DIR)/%,$1) $(PRIVATE_ARSC) $(PRIVATE_LIBS)
+	$(AAPT) compile --package $(LOCAL_PACKAGE) -I $(PRIVATE_ARSC) $(addprefix -I ,$(PRIVATE_LIBS)) -o $(LOCAL_OUT) $$<
+endef
+
+# Compile: out/res/drawable-xhdpi/icon.png <- res/drawable-xhdpi/icon.png
+$(foreach f,$(PRIVATE_INTERMEDIATE_FILES),$(eval $(call make-compile-rule,$f)))
+
+# R.java: gen/com/android/app/R.java <- out/resources.arsc
+# No action since R.java is generated when out/resources.arsc is.
+$(PRIVATE_R_JAVA): $(PRIVATE_ARSC)
+
+# Assemble: zip out/resources.arsc AndroidManifest.xml and res/**/*
+$(PRIVATE_APK_ALIGNED): $(PRIVATE_ARSC) $(PRIVATE_INTERMEDIATE_FILES) $(LOCAL_OUT)/AndroidManifest.xml
+	cd $(LOCAL_OUT); $(ZIP) $(patsubst $(LOCAL_OUT)/%,%,$(PRIVATE_APK_UNALIGNED)) $(patsubst $(LOCAL_OUT)/%,%,$^)
+	$(ZIPALIGN) $(PRIVATE_APK_UNALIGNED) $@
+
+# Create the out directory if needed.
+dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
+
+.PHONY: java
+java: $(PRIVATE_R_JAVA)
+
+.PHONY: assemble
+assemble: $(LOCAL_OUT)/package.apk
+
+.PHONY: all
+all: assemble java
+
+.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/res/drawable/icon.png b/tools/aapt2/data/res/drawable/icon.png
new file mode 100644
index 0000000..4bff9b9
--- /dev/null
+++ b/tools/aapt2/data/res/drawable/icon.png
Binary files differ
diff --git a/tools/aapt2/data/res/drawable/image.xml b/tools/aapt2/data/res/drawable/image.xml
new file mode 100644
index 0000000..9b38739
--- /dev/null
+++ b/tools/aapt2/data/res/drawable/image.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector />
diff --git a/tools/aapt2/data/res/drawable/test.9.png b/tools/aapt2/data/res/drawable/test.9.png
new file mode 100644
index 0000000..33daa11
--- /dev/null
+++ b/tools/aapt2/data/res/drawable/test.9.png
Binary files differ
diff --git a/tools/aapt2/data/res/layout/main.xml b/tools/aapt2/data/res/layout/main.xml
new file mode 100644
index 0000000..5160570
--- /dev/null
+++ b/tools/aapt2/data/res/layout/main.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <variable name="user" type="com.android.User" />
+
+    <View xmlns:app="http://schemas.android.com/apk/res-auto"
+        android:id="@+id/me"
+        android:layout_width="1dp"
+        android:text="@{user.name}"
+        android:layout_height="match_parent"
+        app:layout_width="false"
+        app:flags="complex|weak"
+        android:colorAccent="#ffffff"/>
+</LinearLayout>
diff --git a/tools/aapt2/data/res/values-v4/styles.xml b/tools/aapt2/data/res/values-v4/styles.xml
new file mode 100644
index 0000000..979a82a
--- /dev/null
+++ b/tools/aapt2/data/res/values-v4/styles.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="App" parent="android:Theme.Material">
+        <item name="android:colorAccent">@color/accent</item>
+        <item name="android:text">Hey</item>
+    </style>
+</resources>
diff --git a/tools/aapt2/data/res/values/colors.xml b/tools/aapt2/data/res/values/colors.xml
new file mode 100644
index 0000000..89db5fb
--- /dev/null
+++ b/tools/aapt2/data/res/values/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <color name="primary">#f44336</color>
+    <color name="primary_dark">#b71c1c</color>
+    <color name="accent">#fdd835</color>
+</resources>
diff --git a/tools/aapt2/data/res/values/styles.xml b/tools/aapt2/data/res/values/styles.xml
new file mode 100644
index 0000000..71ce388
--- /dev/null
+++ b/tools/aapt2/data/res/values/styles.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="App" parent="android:Theme.Material">
+        <item name="android:background">@color/primary</item>
+        <item name="android:colorPrimary">@color/primary</item>
+        <item name="android:colorPrimaryDark">@color/primary_dark</item>
+        <item name="android:colorAccent">@color/accent</item>
+    </style>
+    <attr name="custom" format="reference" />
+    <style name="Pop">
+        <item name="custom">@drawable/image</item>
+    </style>
+    <string name="yo">@string/wow</string>
+
+    <declare-styleable name="View">
+        <attr name="custom" />
+        <attr name="decor">
+            <enum name="no-border" value="0"/>
+            <enum name="border" value="1"/>
+            <enum name="shadow" value="2"/>
+        </attr>
+    </declare-styleable>
+
+</resources>
diff --git a/tools/aapt2/data/res/values/test.xml b/tools/aapt2/data/res/values/test.xml
new file mode 100644
index 0000000..d3ead34
--- /dev/null
+++ b/tools/aapt2/data/res/values/test.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
+    <public name="hooha" type="string" id="0x7f020001"/>
+    <string name="wow">@android:string/ok</string>
+    <public name="image" type="drawable" id="0x7f060000" />
+    <attr name="layout_width" format="boolean" />
+    <attr name="flags">
+        <flag name="complex" value="1" />
+        <flag name="pub" value="2" />
+        <flag name="weak" value="4" />
+    </attr>
+</resources>
diff --git a/tools/aapt2/data/resources.arsc b/tools/aapt2/data/resources.arsc
new file mode 100644
index 0000000..6a416df
--- /dev/null
+++ b/tools/aapt2/data/resources.arsc
Binary files differ
diff --git a/tools/aapt2/data/resources_base.arsc b/tools/aapt2/data/resources_base.arsc
new file mode 100644
index 0000000..f9d0610
--- /dev/null
+++ b/tools/aapt2/data/resources_base.arsc
Binary files differ
diff --git a/tools/aapt2/data/resources_hdpi.arsc b/tools/aapt2/data/resources_hdpi.arsc
new file mode 100644
index 0000000..97232a3
--- /dev/null
+++ b/tools/aapt2/data/resources_hdpi.arsc
Binary files differ
diff --git a/tools/aapt2/process.dot b/tools/aapt2/process.dot
new file mode 100644
index 0000000..a92405d
--- /dev/null
+++ b/tools/aapt2/process.dot
@@ -0,0 +1,92 @@
+digraph aapt {
+    out_package [label="out/default/package.apk"];
+    out_fr_package [label="out/fr/package.apk"];
+    out_table_aligned [label="out/default/resources-aligned.arsc"];
+    out_table_fr_aligned [label="out/fr/resources-aligned.arsc"];
+    out_res_layout_main_xml [label="out/res/layout/main.xml"];
+    out_res_layout_v21_main_xml [color=red,label="out/res/layout-v21/main.xml"];
+    out_res_layout_fr_main_xml [label="out/res/layout-fr/main.xml"];
+    out_res_layout_fr_v21_main_xml [color=red,label="out/res/layout-fr-v21/main.xml"];
+    out_table [label="out/default/resources.arsc"];
+    out_fr_table [label="out/fr/resources.arsc"];
+    out_values_table [label="out/values/resources.arsc"];
+    out_layout_table [label="out/layout/resources.arsc"];
+    out_values_fr_table [label="out/values-fr/resources.arsc"];
+    out_layout_fr_table [label="out/layout-fr/resources.arsc"];
+    res_values_strings_xml [label="res/values/strings.xml"];
+    res_values_attrs_xml [label="res/values/attrs.xml"];
+    res_layout_main_xml [label="res/layout/main.xml"];
+    res_layout_fr_main_xml [label="res/layout-fr/main.xml"];
+    res_values_fr_strings_xml [label="res/values-fr/strings.xml"];
+
+    out_package -> package_default;
+    out_fr_package -> package_fr;
+
+    package_default [shape=box,label="Assemble",color=blue];
+    package_default -> out_table_aligned;
+    package_default -> out_res_layout_main_xml;
+    package_default -> out_res_layout_v21_main_xml [color=red];
+
+    package_fr [shape=box,label="Assemble",color=blue];
+    package_fr -> out_table_fr_aligned;
+    package_fr -> out_res_layout_fr_main_xml;
+    package_fr -> out_res_layout_fr_v21_main_xml [color=red];
+
+    out_table_aligned -> align_tables;
+    out_table_fr_aligned -> align_tables;
+
+    align_tables [shape=box,label="Align",color=blue];
+    align_tables -> out_table;
+    align_tables -> out_fr_table;
+
+    out_table -> link_tables;
+
+    link_tables [shape=box,label="Link",color=blue];
+    link_tables -> out_values_table;
+    link_tables -> out_layout_table;
+
+    out_values_table -> compile_values;
+
+    compile_values [shape=box,label="Collect",color=blue];
+    compile_values -> res_values_strings_xml;
+    compile_values -> res_values_attrs_xml;
+
+    out_layout_table -> collect_xml;
+
+    collect_xml [shape=box,label="Collect",color=blue];
+    collect_xml -> res_layout_main_xml;
+
+    out_fr_table -> link_fr_tables;
+
+    link_fr_tables [shape=box,label="Link",color=blue];
+    link_fr_tables -> out_values_fr_table;
+    link_fr_tables -> out_layout_fr_table;
+
+    out_values_fr_table -> compile_values_fr;
+
+    compile_values_fr [shape=box,label="Compile",color=blue];
+    compile_values_fr -> res_values_fr_strings_xml;
+
+    out_layout_fr_table -> collect_xml_fr;
+
+    collect_xml_fr [shape=box,label="Collect",color=blue];
+    collect_xml_fr -> res_layout_fr_main_xml;
+
+    compile_res_layout_main_xml [shape=box,label="Compile",color=blue];
+
+    out_res_layout_main_xml -> compile_res_layout_main_xml;
+
+    out_res_layout_v21_main_xml -> compile_res_layout_main_xml [color=red];
+
+    compile_res_layout_main_xml -> res_layout_main_xml;
+    compile_res_layout_main_xml -> out_table_aligned;
+
+    compile_res_layout_fr_main_xml [shape=box,label="Compile",color=blue];
+
+    out_res_layout_fr_main_xml -> compile_res_layout_fr_main_xml;
+
+    out_res_layout_fr_v21_main_xml -> compile_res_layout_fr_main_xml [color=red];
+
+    compile_res_layout_fr_main_xml -> res_layout_fr_main_xml;
+    compile_res_layout_fr_main_xml -> out_table_fr_aligned;
+}
diff --git a/tools/aapt2/public_attr_map.py b/tools/aapt2/public_attr_map.py
new file mode 100644
index 0000000..92136a8
--- /dev/null
+++ b/tools/aapt2/public_attr_map.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+import sys
+import xml.etree.ElementTree as ET
+
+def findSdkLevelForAttribute(id):
+    intId = int(id, 16)
+    packageId = 0x000000ff & (intId >> 24)
+    typeId = 0x000000ff & (intId >> 16)
+    entryId = 0x0000ffff & intId
+
+    if packageId != 0x01 or typeId != 0x01:
+        return 0
+
+    levels = [(1, 0x021c), (2, 0x021d), (3, 0x0269), (4, 0x028d),
+              (5, 0x02ad), (6, 0x02b3), (7, 0x02b5), (8, 0x02bd),
+              (9, 0x02cb), (11, 0x0361), (12, 0x0366), (13, 0x03a6),
+              (16, 0x03ae), (17, 0x03cc), (18, 0x03da), (19, 0x03f1),
+              (20, 0x03f6), (21, 0x04ce)]
+    for level, attrEntryId in levels:
+        if entryId <= attrEntryId:
+            return level
+    return 22
+
+
+tree = None
+with open(sys.argv[1], 'rt') as f:
+    tree = ET.parse(f)
+
+attrs = []
+for node in tree.iter('public'):
+    if node.get('type') == 'attr':
+        sdkLevel = findSdkLevelForAttribute(node.get('id', '0'))
+        if sdkLevel > 1 and sdkLevel < 22:
+            attrs.append("{{ u\"{}\", {} }}".format(node.get('name'), sdkLevel))
+
+print "#include <string>"
+print "#include <unordered_map>"
+print
+print "namespace aapt {"
+print
+print "static std::unordered_map<std::u16string, size_t> sAttrMap = {"
+print ",\n    ".join(attrs)
+print "};"
+print
+print "size_t findAttributeSdkLevel(const std::u16string& name) {"
+print "    auto iter = sAttrMap.find(name);"
+print "    if (iter != sAttrMap.end()) {"
+print "        return iter->second;"
+print "    }"
+print "    return 0;"
+print "}"
+print
+print "} // namespace aapt"
+print
diff --git a/tools/aapt2/todo.txt b/tools/aapt2/todo.txt
new file mode 100644
index 0000000..acc8bfb
--- /dev/null
+++ b/tools/aapt2/todo.txt
@@ -0,0 +1,29 @@
+XML Files
+X Collect declared IDs
+X Build StringPool
+X Flatten
+
+Resource Table Operations
+X Build Resource Table (with StringPool) from XML.
+X Modify Resource Table.
+X - Copy and transform resources.
+X   - Pre-17/21 attr correction.
+X Perform analysis of types.
+X Flatten.
+X Assign resource IDs.
+X Assign public resource IDs.
+X Merge resource tables
+- Assign private attributes to different typespace.
+- Align resource tables
+
+Splits
+- Collect all resources (ids from layouts).
+- Generate resource table from base resources.
+- Generate resource table from individual resources of the required type.
+- Align resource tables (same type/name = same ID).
+
+Fat Apk
+X Collect all resources (ids from layouts).
+X Generate resource tables for all configurations.
+- Align individual resource tables.
+- Merge resource tables.
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 72ee343..df76bc9 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -518,7 +518,7 @@
             if m.name.startswith("create") and m.name.endswith("Intent"):
                 pass
             else:
-                error(clazz, m, "FW1", "Methods creating an Intent must be named createFooIntent()")
+                warn(clazz, m, "FW1", "Methods creating an Intent should be named createFooIntent()")
 
 
 def verify_helper_classes(clazz):
diff --git a/tools/layoutlib/rename_font/build_font.py b/tools/layoutlib/rename_font/build_font.py
index c747d92..9713a4c 100755
--- a/tools/layoutlib/rename_font/build_font.py
+++ b/tools/layoutlib/rename_font/build_font.py
@@ -209,15 +209,18 @@
 
 
 def get_version(string):
-  # 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 '):
-    raise InvalidFontException('mal-formed font version')
-  return sanitize(string.split()[1])
+  # The spec says that the version string should start with "Version ". But not
+  # all fonts do. So, we return the complete string if it doesn't start with
+  # the prefix, else we return the rest of the string after sanitizing it.
+  prefix = 'Version '
+  if string.startswith(prefix):
+    string = string[len(prefix):]
+  return sanitize(string)
 
 
 def sanitize(string):
+  """ Remove non-standard chars. """
   return re.sub(r'[^\w-]+', '', string)
 
 if __name__ == '__main__':
diff --git a/tools/layoutlib/rename_font/build_font_single.py b/tools/layoutlib/rename_font/build_font_single.py
index 5f7dad9..4245cdc 100755
--- a/tools/layoutlib/rename_font/build_font_single.py
+++ b/tools/layoutlib/rename_font/build_font_single.py
@@ -193,15 +193,18 @@
 
 
 def get_version(string):
-  # 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 '):
-    raise InvalidFontException('mal-formed font version')
-  return sanitize(string.split()[1])
+  # The spec says that the version string should start with "Version ". But not
+  # all fonts do. So, we return the complete string if it doesn't start with
+  # the prefix, else we return the rest of the string after sanitizing it.
+  prefix = 'Version '
+  if string.startswith(prefix):
+    string = string[len(prefix):]
+  return sanitize(string)
 
 
 def sanitize(string):
+  """ Remove non-standard chars. """
   return re.sub(r'[^\w-]+', '', string)
 
 if __name__ == '__main__':
diff --git a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
index 9284796..0f73342 100644
--- a/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
+++ b/wifi/java/android/net/wifi/WifiActivityEnergyInfo.java
@@ -141,6 +141,7 @@
         return (int)mControllerIdleTimeMs;
     }
 
+
     /**
      * product of current(mA), voltage(V) and time(ms)
      * @return energy used
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 36fc96b..440ad61 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -235,8 +235,10 @@
         public static final int SIM     = 4;
         /** EAP-Authentication and Key Agreement */
         public static final int AKA     = 5;
+        /** EAP-Authentication and Key Agreement Prime */
+        public static final int AKA_PRIME = 6;
         /** @hide */
-        public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA" };
+        public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'" };
 
         /** Prevent initialization */
         private Eap() {}
@@ -286,6 +288,7 @@
             case Eap.TTLS:
             case Eap.SIM:
             case Eap.AKA:
+            case Eap.AKA_PRIME:
                 mFields.put(EAP_KEY, Eap.strings[eapMethod]);
                 mFields.put(OPP_KEY_CACHING, "1");
                 break;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 6371891..275c7d1 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -861,6 +861,14 @@
     public static final int WIFI_FEATURE_TDLS_OFFCHANNEL  = 0x2000;  // Support for TDLS off channel
     /** @hide */
     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
+    /** @hide */
+    public static final int WIFI_FEATURE_AP_STA            = 0x8000;  // Support for AP STA Concurrency
+    /** @hide */
+    public static final int WIFI_FEATURE_LINK_LAYER_STATS  = 0x10000; // Link layer stats collection
+    /** @hide */
+    public static final int WIFI_FEATURE_LOGGER            = 0x20000; // WiFi Logger
+    /** @hide */
+    public static final int WIFI_FEATURE_HAL_EPNO          = 0x40000; // WiFi PNO enhanced
 
     private int getSupportedFeatures() {
         try {
@@ -972,7 +980,7 @@
      * @return true if this adapter supports advanced power/performance counters
      */
     public boolean isEnhancedPowerReportingSupported() {
-        return isFeatureSupported(WIFI_FEATURE_EPR);
+        return isFeatureSupported(WIFI_FEATURE_LINK_LAYER_STATS);
     }
 
     /**