Merge "Fix fingerprint API for 3rd party apps"
diff --git a/Android.mk b/Android.mk
index f4b9551..d7e8e4e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -209,6 +209,7 @@
 	core/java/android/security/IKeystoreService.aidl \
 	core/java/android/service/carrier/ICarrierMessagingCallback.aidl \
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
+	core/java/android/service/gatekeeper/IGateKeeperService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
@@ -1017,13 +1018,13 @@
 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_DROIDDOC_HTML_DIR:=docs/html-ndk
 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_MODULE := online-ndk
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
diff --git a/api/current.txt b/api/current.txt
index 6de9a03..fdeda0b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3555,6 +3555,7 @@
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
+    method public int getPackageImportance(java.lang.String);
     method public android.os.Debug.MemoryInfo[] getProcessMemoryInfo(int[]);
     method public java.util.List<android.app.ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
     method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException;
@@ -3647,9 +3648,11 @@
     field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190
     field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4
     field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
+    field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
     field public static final int IMPORTANCE_GONE = 1000; // 0x3e8
     field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82
     field public static final int IMPORTANCE_SERVICE = 300; // 0x12c
+    field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96
     field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8
     field public static final int REASON_PROVIDER_IN_USE = 1; // 0x1
     field public static final int REASON_SERVICE_IN_USE = 2; // 0x2
@@ -4596,6 +4599,7 @@
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
+    method public boolean isDeviceSecure();
     method public boolean isKeyguardLocked();
     method public boolean isKeyguardSecure();
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
@@ -5653,6 +5657,7 @@
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public boolean getAutoTimeRequired();
+    method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
@@ -5662,6 +5667,7 @@
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public android.app.admin.OtaPolicy getOtaPolicy();
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5703,16 +5709,19 @@
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
+    method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
+    method public boolean setKeyguardEnabledState(android.content.ComponentName, boolean);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOtaPolicy(android.content.ComponentName, android.app.admin.OtaPolicy);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
     method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -5742,6 +5751,7 @@
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+    field public static final java.lang.String ACTION_OTA_POLICY_CHANGED = "android.app.action.OTA_POLICY_CHANGED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -5809,6 +5819,23 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public class OtaPolicy {
+    ctor public OtaPolicy();
+    method public int getInstallWindowEnd();
+    method public int getInstallWindowStart();
+    method public int getPolicyType();
+    method public void setAutomaticInstallPolicy();
+    method public void setPostponeInstallPolicy();
+    method public void setWindowedInstallPolicy(int, int) throws android.app.admin.OtaPolicy.InvalidWindowException;
+    field public static final int TYPE_INSTALL_AUTOMATIC = 1; // 0x1
+    field public static final int TYPE_INSTALL_WINDOWED = 2; // 0x2
+    field public static final int TYPE_POSTPONE = 3; // 0x3
+  }
+
+  public static class OtaPolicy.InvalidWindowException extends java.lang.Exception {
+    ctor public OtaPolicy.InvalidWindowException(java.lang.String);
+  }
+
 }
 
 package android.app.backup {
@@ -8157,6 +8184,7 @@
     field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
     field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
     field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final java.lang.String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
     field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
     field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
     field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
@@ -13023,6 +13051,8 @@
     method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void close();
     method public abstract android.hardware.camera2.CameraDevice getDevice();
+    method public abstract android.view.Surface getInputSurface();
+    method public abstract boolean isReprocessible();
     method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
@@ -13138,6 +13168,8 @@
     method public abstract void close();
     method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessibleCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract java.lang.String getId();
     field public static final int TEMPLATE_MANUAL = 6; // 0x6
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
@@ -13388,6 +13420,7 @@
     method public int describeContents();
     method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public java.lang.Object getTag();
+    method public boolean isReprocess();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> BLACK_LEVEL_LOCK;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE;
@@ -13592,6 +13625,13 @@
     field public static final int SCORE_MIN = 1; // 0x1
   }
 
+  public final class InputConfiguration {
+    ctor public InputConfiguration(int, int, int);
+    method public int getFormat();
+    method public int getHeight();
+    method public int getWidth();
+  }
+
   public final class LensShadingMap {
     method public void copyGainFactors(float[], int);
     method public int getColumnCount();
@@ -14799,7 +14839,7 @@
     method public static float getMaxVolume();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
-    method protected deprecated int getNativeFrameCount();
+    method public int getNativeFrameCount() throws java.lang.IllegalStateException;
     method public static int getNativeOutputSampleRate(int);
     method public int getNotificationMarkerPosition();
     method public int getPlayState();
@@ -15184,6 +15224,7 @@
     method public android.media.MediaCodecInfo.AudioCapabilities getAudioCapabilities();
     method public android.media.MediaFormat getDefaultFormat();
     method public android.media.MediaCodecInfo.EncoderCapabilities getEncoderCapabilities();
+    method public int getMaxSupportedInstances();
     method public java.lang.String getMimeType();
     method public android.media.MediaCodecInfo.VideoCapabilities getVideoCapabilities();
     method public final boolean isFeatureRequired(java.lang.String);
@@ -18053,6 +18094,7 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
+    method public boolean contains(java.net.InetAddress);
     method public int describeContents();
     method public java.net.InetAddress getAddress();
     method public int getPrefixLength();
@@ -28383,8 +28425,10 @@
   public final class ChooserTarget implements android.os.Parcelable {
     ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
     ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.Intent);
     method public int describeContents();
     method public android.graphics.Bitmap getIcon();
+    method public android.content.Intent getIntent();
     method public android.content.IntentSender getIntentSender();
     method public float getScore();
     method public java.lang.CharSequence getTitle();
@@ -28397,6 +28441,8 @@
     ctor public ChooserTargetService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+    field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+    field public static final java.lang.String META_DATA_NAME = "android.service.chooser.chooser_target_service";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
   }
 
@@ -28634,7 +28680,7 @@
     field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
 
-  public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
+  public abstract class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
     method public void finish();
@@ -28650,6 +28696,7 @@
     method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
     method public void onCompleteVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
+    method public void onConfigurationChanged(android.content.res.Configuration);
     method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onCreate(android.os.Bundle, int);
     method public android.view.View onCreateContentView();
@@ -28662,10 +28709,12 @@
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onLowMemory();
     method public abstract void onPickOption(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle);
     method public void onShow(android.os.Bundle, int);
     method public void onTaskFinished(android.content.Intent, int);
     method public void onTaskStarted(android.content.Intent, int);
+    method public void onTrimMemory(int);
     method public void setContentView(android.view.View);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
@@ -35538,6 +35587,8 @@
     field public static final int TEXT_ALIGNMENT_VIEW_START = 5; // 0x5
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; // 0x6
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; // 0x7
     field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
     field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
diff --git a/api/removed.txt b/api/removed.txt
index 0c433c3..326b05d 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,3 +1,12 @@
+package android {
+
+  public static final class Manifest.permission {
+    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";
+  }
+
+}
+
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 708394c..deaf916 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3644,6 +3644,7 @@
     method public int getMemoryClass();
     method public void getMemoryInfo(android.app.ActivityManager.MemoryInfo);
     method public static void getMyMemoryState(android.app.ActivityManager.RunningAppProcessInfo);
+    method public int getPackageImportance(java.lang.String);
     method public android.os.Debug.MemoryInfo[] getProcessMemoryInfo(int[]);
     method public java.util.List<android.app.ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState();
     method public deprecated java.util.List<android.app.ActivityManager.RecentTaskInfo> getRecentTasks(int, int) throws java.lang.SecurityException;
@@ -3736,9 +3737,11 @@
     field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190
     field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4
     field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64
+    field public static final int IMPORTANCE_FOREGROUND_SERVICE = 125; // 0x7d
     field public static final int IMPORTANCE_GONE = 1000; // 0x3e8
     field public static final int IMPORTANCE_PERCEPTIBLE = 130; // 0x82
     field public static final int IMPORTANCE_SERVICE = 300; // 0x12c
+    field public static final int IMPORTANCE_TOP_SLEEPING = 150; // 0x96
     field public static final int IMPORTANCE_VISIBLE = 200; // 0xc8
     field public static final int REASON_PROVIDER_IN_USE = 1; // 0x1
     field public static final int REASON_SERVICE_IN_USE = 2; // 0x2
@@ -4687,6 +4690,7 @@
     method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult);
     method public boolean inKeyguardRestrictedInputMode();
     method public boolean isDeviceLocked();
+    method public boolean isDeviceSecure();
     method public boolean isKeyguardLocked();
     method public boolean isKeyguardSecure();
     method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String);
@@ -5749,6 +5753,7 @@
     method public java.util.List<android.content.ComponentName> getActiveAdmins();
     method public android.os.Bundle getApplicationRestrictions(android.content.ComponentName, java.lang.String);
     method public boolean getAutoTimeRequired();
+    method public boolean getBluetoothContactSharingDisabled(android.content.ComponentName);
     method public boolean getCameraDisabled(android.content.ComponentName);
     method public java.lang.String getCertInstallerPackage(android.content.ComponentName) throws java.lang.SecurityException;
     method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
@@ -5761,6 +5766,7 @@
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
+    method public android.app.admin.OtaPolicy getOtaPolicy();
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
     method public int getPasswordHistoryLength(android.content.ComponentName);
@@ -5807,16 +5813,19 @@
     method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
     method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
     method public void setAutoTimeRequired(android.content.ComponentName, boolean);
+    method public void setBluetoothContactSharingDisabled(android.content.ComponentName, boolean);
     method public void setCameraDisabled(android.content.ComponentName, boolean);
     method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
     method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
     method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
+    method public boolean setKeyguardEnabledState(android.content.ComponentName, boolean);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
+    method public void setOtaPolicy(android.content.ComponentName, android.app.admin.OtaPolicy);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
     method public void setPasswordMinimumLength(android.content.ComponentName, int);
@@ -5846,6 +5855,7 @@
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+    field public static final java.lang.String ACTION_OTA_POLICY_CHANGED = "android.app.action.OTA_POLICY_CHANGED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SEND_DEVICE_INITIALIZER_STATUS = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
@@ -5918,6 +5928,23 @@
     field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
   }
 
+  public class OtaPolicy {
+    ctor public OtaPolicy();
+    method public int getInstallWindowEnd();
+    method public int getInstallWindowStart();
+    method public int getPolicyType();
+    method public void setAutomaticInstallPolicy();
+    method public void setPostponeInstallPolicy();
+    method public void setWindowedInstallPolicy(int, int) throws android.app.admin.OtaPolicy.InvalidWindowException;
+    field public static final int TYPE_INSTALL_AUTOMATIC = 1; // 0x1
+    field public static final int TYPE_INSTALL_WINDOWED = 2; // 0x2
+    field public static final int TYPE_POSTPONE = 3; // 0x3
+  }
+
+  public static class OtaPolicy.InvalidWindowException extends java.lang.Exception {
+    ctor public OtaPolicy.InvalidWindowException(java.lang.String);
+  }
+
 }
 
 package android.app.backup {
@@ -8383,6 +8410,7 @@
     field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list";
     field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list";
     field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list";
+    field public static final java.lang.String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
     field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT";
     field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER";
     field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
@@ -13319,6 +13347,8 @@
     method public abstract int captureBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void close();
     method public abstract android.hardware.camera2.CameraDevice getDevice();
+    method public abstract android.view.Surface getInputSurface();
+    method public abstract boolean isReprocessible();
     method public abstract int setRepeatingBurst(java.util.List<android.hardware.camera2.CaptureRequest>, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract int setRepeatingRequest(android.hardware.camera2.CaptureRequest, android.hardware.camera2.CameraCaptureSession.CaptureCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract void stopRepeating() throws android.hardware.camera2.CameraAccessException;
@@ -13434,6 +13464,8 @@
     method public abstract void close();
     method public abstract android.hardware.camera2.CaptureRequest.Builder createCaptureRequest(int) throws android.hardware.camera2.CameraAccessException;
     method public abstract void createCaptureSession(java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
+    method public abstract android.hardware.camera2.CaptureRequest.Builder createReprocessCaptureRequest(android.hardware.camera2.TotalCaptureResult) throws android.hardware.camera2.CameraAccessException;
+    method public abstract void createReprocessibleCaptureSession(android.hardware.camera2.params.InputConfiguration, java.util.List<android.view.Surface>, android.hardware.camera2.CameraCaptureSession.StateCallback, android.os.Handler) throws android.hardware.camera2.CameraAccessException;
     method public abstract java.lang.String getId();
     field public static final int TEMPLATE_MANUAL = 6; // 0x6
     field public static final int TEMPLATE_PREVIEW = 1; // 0x1
@@ -13684,6 +13716,7 @@
     method public int describeContents();
     method public T get(android.hardware.camera2.CaptureRequest.Key<T>);
     method public java.lang.Object getTag();
+    method public boolean isReprocess();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> BLACK_LEVEL_LOCK;
     field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE;
@@ -13888,6 +13921,13 @@
     field public static final int SCORE_MIN = 1; // 0x1
   }
 
+  public final class InputConfiguration {
+    ctor public InputConfiguration(int, int, int);
+    method public int getFormat();
+    method public int getHeight();
+    method public int getWidth();
+  }
+
   public final class LensShadingMap {
     method public void copyGainFactors(float[], int);
     method public int getColumnCount();
@@ -16011,7 +16051,7 @@
     method public static float getMaxVolume();
     method public static int getMinBufferSize(int, int, int);
     method public static float getMinVolume();
-    method protected deprecated int getNativeFrameCount();
+    method public int getNativeFrameCount() throws java.lang.IllegalStateException;
     method public static int getNativeOutputSampleRate(int);
     method public int getNotificationMarkerPosition();
     method public int getPlayState();
@@ -16396,6 +16436,7 @@
     method public android.media.MediaCodecInfo.AudioCapabilities getAudioCapabilities();
     method public android.media.MediaFormat getDefaultFormat();
     method public android.media.MediaCodecInfo.EncoderCapabilities getEncoderCapabilities();
+    method public int getMaxSupportedInstances();
     method public java.lang.String getMimeType();
     method public android.media.MediaCodecInfo.VideoCapabilities getVideoCapabilities();
     method public final boolean isFeatureRequired(java.lang.String);
@@ -19507,6 +19548,7 @@
   }
 
   public final class IpPrefix implements android.os.Parcelable {
+    method public boolean contains(java.net.InetAddress);
     method public int describeContents();
     method public java.net.InetAddress getAddress();
     method public int getPrefixLength();
@@ -30382,8 +30424,10 @@
   public final class ChooserTarget implements android.os.Parcelable {
     ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.app.PendingIntent);
     ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.IntentSender);
+    ctor public ChooserTarget(java.lang.CharSequence, android.graphics.Bitmap, float, android.content.Intent);
     method public int describeContents();
     method public android.graphics.Bitmap getIcon();
+    method public android.content.Intent getIntent();
     method public android.content.IntentSender getIntentSender();
     method public float getScore();
     method public java.lang.CharSequence getTitle();
@@ -30396,6 +30440,8 @@
     ctor public ChooserTargetService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public abstract java.util.List<android.service.chooser.ChooserTarget> onGetChooserTargets(android.content.ComponentName, android.content.IntentFilter);
+    field public static final java.lang.String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+    field public static final java.lang.String META_DATA_NAME = "android.service.chooser.chooser_target_service";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
   }
 
@@ -30730,7 +30776,7 @@
     field public static final int START_WITH_SCREENSHOT = 2; // 0x2
   }
 
-  public abstract class VoiceInteractionSession implements android.view.KeyEvent.Callback {
+  public abstract class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback {
     ctor public VoiceInteractionSession(android.content.Context);
     ctor public VoiceInteractionSession(android.content.Context, android.os.Handler);
     method public void finish();
@@ -30746,6 +30792,7 @@
     method public abstract void onCommand(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.String, android.os.Bundle);
     method public void onCompleteVoice(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onComputeInsets(android.service.voice.VoiceInteractionSession.Insets);
+    method public void onConfigurationChanged(android.content.res.Configuration);
     method public abstract void onConfirm(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.os.Bundle);
     method public void onCreate(android.os.Bundle, int);
     method public android.view.View onCreateContentView();
@@ -30758,10 +30805,12 @@
     method public boolean onKeyLongPress(int, android.view.KeyEvent);
     method public boolean onKeyMultiple(int, int, android.view.KeyEvent);
     method public boolean onKeyUp(int, android.view.KeyEvent);
+    method public void onLowMemory();
     method public abstract void onPickOption(android.service.voice.VoiceInteractionSession.Caller, android.service.voice.VoiceInteractionSession.Request, java.lang.CharSequence, android.app.VoiceInteractor.PickOptionRequest.Option[], android.os.Bundle);
     method public void onShow(android.os.Bundle, int);
     method public void onTaskFinished(android.content.Intent, int);
     method public void onTaskStarted(android.content.Intent, int);
+    method public void onTrimMemory(int);
     method public void setContentView(android.view.View);
     method public void setKeepAwake(boolean);
     method public void setTheme(int);
@@ -38159,6 +38208,8 @@
     field public static final int TEXT_ALIGNMENT_VIEW_START = 5; // 0x5
     field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2
     field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; // 0x6
+    field public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; // 0x7
     field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0
     field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5
     field public static final int TEXT_DIRECTION_LTR = 3; // 0x3
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 0c433c3..326b05d 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,3 +1,12 @@
+package android {
+
+  public static final class Manifest.permission {
+    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";
+  }
+
+}
+
 package android.content.pm {
 
   public class PackageInfo implements android.os.Parcelable {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 908d46e..fa28143 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -124,6 +124,7 @@
                 "       am restart\n" +
                 "       am idle-maintenance\n" +
                 "       am screen-compat [on|off] <PACKAGE>\n" +
+                "       am package-importance <PACKAGE>\n" +
                 "       am to-uri [INTENT]\n" +
                 "       am to-intent-uri [INTENT]\n" +
                 "       am to-app-uri [INTENT]\n" +
@@ -233,6 +234,8 @@
                 "\n" +
                 "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
                 "\n" +
+                "am package-importance: print current importance of <PACKAGE>.\n" +
+                "\n" +
                 "am to-uri: print the given Intent specification as a URI.\n" +
                 "\n" +
                 "am to-intent-uri: print the given Intent specification as an intent: URI.\n" +
@@ -365,6 +368,8 @@
             runIdleMaintenance();
         } else if (op.equals("screen-compat")) {
             runScreenCompat();
+        } else if (op.equals("package-importance")) {
+            runPackageImportance();
         } else if (op.equals("to-uri")) {
             runToUri(0);
         } else if (op.equals("to-intent-uri")) {
@@ -1604,6 +1609,16 @@
         } while (packageName != null);
     }
 
+    private void runPackageImportance() throws Exception {
+        String packageName = nextArgRequired();
+        try {
+            int procState = mAm.getPackageProcessState(packageName);
+            System.out.println(
+                    ActivityManager.RunningAppProcessInfo.procStateToImportance(procState));
+        } catch (RemoteException e) {
+        }
+    }
+
     private void runToUri(int flags) throws Exception {
         Intent intent = makeIntent(UserHandle.USER_CURRENT);
         System.out.println(intent.toUri(flags));
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2b35cd4..51ececc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -2010,27 +2010,47 @@
         public int lastTrimLevel;
 
         /**
-         * Constant for {@link #importance}: this process is running the
-         * foreground UI.
+         * Constant for {@link #importance}: This process is running the
+         * foreground UI; that is, it is the thing currently at the top of the screen
+         * that the user is interacting with.
          */
         public static final int IMPORTANCE_FOREGROUND = 100;
         
         /**
-         * Constant for {@link #importance}: this process is running something
+         * Constant for {@link #importance}: This process is running a foreground
+         * service, for example to perform music playback even while the user is
+         * not immediately in the app.  This generally indicates that the process
+         * is doing something the user actively cares about.
+         */
+        public static final int IMPORTANCE_FOREGROUND_SERVICE = 125;
+
+        /**
+         * Constant for {@link #importance}: This process is running the foreground
+         * UI, but the device is asleep so it is not visible to the user.  This means
+         * the user is not really aware of the process, because they can not see or
+         * interact with it, but it is quite important because it what they expect to
+         * return to once unlocking the device.
+         */
+        public static final int IMPORTANCE_TOP_SLEEPING = 150;
+
+        /**
+         * Constant for {@link #importance}: This process is running something
          * that is actively visible to the user, though not in the immediate
-         * foreground.
+         * foreground.  This may be running a window that is behind the current
+         * foreground (so paused and with its state saved, not interacting with
+         * the user, but visible to them to some degree); it may also be running
+         * other services under the system's control that it inconsiders important.
          */
         public static final int IMPORTANCE_VISIBLE = 200;
         
         /**
-         * Constant for {@link #importance}: this process is running something
-         * that is considered to be actively perceptible to the user.  An
-         * example would be an application performing background music playback.
+         * Constant for {@link #importance}: This process is not something the user
+         * is directly aware of, but is otherwise perceptable to them to some degree.
          */
         public static final int IMPORTANCE_PERCEPTIBLE = 130;
         
         /**
-         * Constant for {@link #importance}: this process is running an
+         * Constant for {@link #importance}: This process is running an
          * application that can not save its state, and thus can't be killed
          * while in the background.
          * @hide
@@ -2038,42 +2058,51 @@
         public static final int IMPORTANCE_CANT_SAVE_STATE = 170;
         
         /**
-         * Constant for {@link #importance}: this process is contains services
-         * that should remain running.
+         * Constant for {@link #importance}: This process is contains services
+         * that should remain running.  These are background services apps have
+         * started, not something the user is aware of, so they may be killed by
+         * the system relatively freely (though it is generally desired that they
+         * stay running as long as they want to).
          */
         public static final int IMPORTANCE_SERVICE = 300;
         
         /**
-         * Constant for {@link #importance}: this process process contains
+         * Constant for {@link #importance}: This process process contains
          * background code that is expendable.
          */
         public static final int IMPORTANCE_BACKGROUND = 400;
         
         /**
-         * Constant for {@link #importance}: this process is empty of any
+         * Constant for {@link #importance}: This process is empty of any
          * actively running code.
          */
         public static final int IMPORTANCE_EMPTY = 500;
 
         /**
-         * Constant for {@link #importance}: this process does not exist.
+         * Constant for {@link #importance}: This process does not exist.
          */
         public static final int IMPORTANCE_GONE = 1000;
 
         /** @hide */
         public static int procStateToImportance(int procState) {
-            if (procState >= ActivityManager.PROCESS_STATE_HOME) {
-                return ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
-            } else if (procState >= ActivityManager.PROCESS_STATE_SERVICE) {
-                return ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
-            } else if (procState > ActivityManager.PROCESS_STATE_HEAVY_WEIGHT) {
-                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_FOREGROUND_SERVICE) {
-                return ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
+            if (procState == PROCESS_STATE_NONEXISTENT) {
+                return IMPORTANCE_GONE;
+            } else if (procState >= PROCESS_STATE_HOME) {
+                return IMPORTANCE_BACKGROUND;
+            } else if (procState >= PROCESS_STATE_SERVICE) {
+                return IMPORTANCE_SERVICE;
+            } else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
+                return IMPORTANCE_CANT_SAVE_STATE;
+            } else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
+                return IMPORTANCE_PERCEPTIBLE;
+            } else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
+                return IMPORTANCE_VISIBLE;
+            } else if (procState >= PROCESS_STATE_TOP_SLEEPING) {
+                return IMPORTANCE_TOP_SLEEPING;
+            } else if (procState >= PROCESS_STATE_FOREGROUND_SERVICE) {
+                return IMPORTANCE_FOREGROUND_SERVICE;
             } else {
-                return ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+                return IMPORTANCE_FOREGROUND;
             }
         }
 
@@ -2253,6 +2282,22 @@
     }
 
     /**
+     * Return the importance of a given package name, based on the processes that are
+     * currently running.  The return value is one of the importance constants defined
+     * in {@link RunningAppProcessInfo}, giving you the highest importance of all the
+     * processes that this package has code running inside of.  If there are no processes
+     * running its code, {@link RunningAppProcessInfo#IMPORTANCE_GONE} is returned.
+     */
+    public int getPackageImportance(String packageName) {
+        try {
+            int procState = ActivityManagerNative.getDefault().getPackageProcessState(packageName);
+            return RunningAppProcessInfo.procStateToImportance(procState);
+        } catch (RemoteException e) {
+            return RunningAppProcessInfo.IMPORTANCE_GONE;
+        }
+    }
+
+    /**
      * Return global memory state information for the calling process.  This
      * does not fill in all fields of the {@link RunningAppProcessInfo}.  The
      * only fields that will be filled in are
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index f63d13c..256d87d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -106,9 +106,24 @@
         }
     }
 
-    static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg) {
+    static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
+            String tag) {
         try {
-            getDefault().noteWakeupAlarm(ps.getTarget(), sourceUid, sourcePkg);
+            getDefault().noteWakeupAlarm(ps.getTarget(), sourceUid, sourcePkg, tag);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    static public void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
+        try {
+            getDefault().noteAlarmStart(ps.getTarget(), sourceUid, tag);
+        } catch (RemoteException ex) {
+        }
+    }
+
+    static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
+        try {
+            getDefault().noteAlarmFinish(ps.getTarget(), sourceUid, tag);
         } catch (RemoteException ex) {
         }
     }
@@ -1375,7 +1390,30 @@
                     data.readStrongBinder());
             int sourceUid = data.readInt();
             String sourcePkg = data.readString();
-            noteWakeupAlarm(is, sourceUid, sourcePkg);
+            String tag = data.readString();
+            noteWakeupAlarm(is, sourceUid, sourcePkg, tag);
+            reply.writeNoException();
+            return true;
+        }
+
+        case NOTE_ALARM_START_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IIntentSender is = IIntentSender.Stub.asInterface(
+                    data.readStrongBinder());
+            int sourceUid = data.readInt();
+            String tag = data.readString();
+            noteAlarmStart(is, sourceUid, tag);
+            reply.writeNoException();
+            return true;
+        }
+
+        case NOTE_ALARM_FINISH_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IIntentSender is = IIntentSender.Stub.asInterface(
+                    data.readStrongBinder());
+            int sourceUid = data.readInt();
+            String tag = data.readString();
+            noteAlarmFinish(is, sourceUid, tag);
             reply.writeNoException();
             return true;
         }
@@ -2461,6 +2499,15 @@
             reply.writeNoException();
             return true;
         }
+
+        case GET_PACKAGE_PROCESS_STATE_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String pkg = data.readString();
+            int res = getPackageProcessState(pkg);
+            reply.writeNoException();
+            reply.writeInt(res);
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -3304,7 +3351,7 @@
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(stackBoxId);
         r.writeToParcel(data, 0);
-        mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(RESIZE_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -3360,7 +3407,7 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(stackId);
-        mRemote.transact(SET_FOCUSED_STACK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(SET_FOCUSED_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -3384,7 +3431,7 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(listener.asBinder());
-        mRemote.transact(REGISTER_TASK_STACK_LISTENER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(REGISTER_TASK_STACK_LISTENER_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -4214,16 +4261,37 @@
         mRemote.transact(ENTER_SAFE_MODE_TRANSACTION, data, null, 0);
         data.recycle();
     }
-    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg)
+    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(sender.asBinder());
         data.writeInt(sourceUid);
         data.writeString(sourcePkg);
+        data.writeString(tag);
         mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
         data.recycle();
     }
+    public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(sender.asBinder());
+        data.writeInt(sourceUid);
+        data.writeString(tag);
+        mRemote.transact(NOTE_ALARM_START_TRANSACTION, data, null, 0);
+        data.recycle();
+    }
+    public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag)
+            throws RemoteException {
+        Parcel data = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(sender.asBinder());
+        data.writeInt(sourceUid);
+        data.writeString(tag);
+        mRemote.transact(NOTE_ALARM_FINISH_TRANSACTION, data, null, 0);
+        data.recycle();
+    }
     public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
@@ -5486,7 +5554,7 @@
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
         values.writeToParcel(data, 0);
-        mRemote.transact(SET_TASK_DESCRIPTION_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(SET_TASK_DESCRIPTION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5499,7 +5567,7 @@
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(taskId);
         data.writeInt(resizeable ? 1 : 0);
-        mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(SET_TASK_RESIZEABLE_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5513,7 +5581,7 @@
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(taskId);
         r.writeToParcel(data, 0);
-        mRemote.transact(RESIZE_TASK_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(RESIZE_TASK_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5545,7 +5613,7 @@
             data.writeInt(1);
             data.writeBundle(options.toBundle());
         }
-        mRemote.transact(START_IN_PLACE_ANIMATION_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(START_IN_PLACE_ANIMATION_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5586,8 +5654,7 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        mRemote.transact(BACKGROUND_RESOURCES_RELEASED_TRANSACTION, data, reply,
-                IBinder.FLAG_ONEWAY);
+        mRemote.transact(BACKGROUND_RESOURCES_RELEASED_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5599,8 +5666,7 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        mRemote.transact(NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION, data, reply,
-                IBinder.FLAG_ONEWAY);
+        mRemote.transact(NOTIFY_LAUNCH_TASK_BEHIND_COMPLETE_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5612,8 +5678,7 @@
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        mRemote.transact(NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION, data, reply,
-                IBinder.FLAG_ONEWAY);
+        mRemote.transact(NOTIFY_ENTER_ANIMATION_COMPLETE_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
@@ -5703,11 +5768,25 @@
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(userId);
         data.writeStringArray(packages);
-        mRemote.transact(UPDATE_LOCK_TASK_PACKAGES_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
+        mRemote.transact(UPDATE_LOCK_TASK_PACKAGES_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
 
+    @Override
+    public int getPackageProcessState(String packageName) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(packageName);
+        mRemote.transact(GET_PACKAGE_PROCESS_STATE_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 9ddfd88..907ae26 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -17,6 +17,8 @@
 package android.app;
 
 import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.XmlRes;
 import android.content.ComponentName;
@@ -733,13 +735,16 @@
         }
     }
 
-    @Override public Drawable getDrawable(String packageName, @DrawableRes int resid,
-                                          ApplicationInfo appInfo) {
-        ResourceName name = new ResourceName(packageName, resid);
-        Drawable dr = getCachedIcon(name);
-        if (dr != null) {
-            return dr;
+    @Nullable
+    @Override
+    public Drawable getDrawable(String packageName, @DrawableRes int resId,
+            @Nullable ApplicationInfo appInfo) {
+        final ResourceName name = new ResourceName(packageName, resId);
+        final Drawable cachedIcon = getCachedIcon(name);
+        if (cachedIcon != null) {
+            return cachedIcon;
         }
+
         if (appInfo == null) {
             try {
                 appInfo = getApplicationInfo(packageName, sDefaultFlags);
@@ -747,36 +752,44 @@
                 return null;
             }
         }
-        try {
-            Resources r = getResourcesForApplication(appInfo);
-            dr = r.getDrawable(resid);
-            if (false) {
-                RuntimeException e = new RuntimeException("here");
-                e.fillInStackTrace();
-                Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
-                      + " from package " + packageName
-                      + ": app scale=" + r.getCompatibilityInfo().applicationScale
-                      + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
-                      e);
+
+        if (resId != 0) {
+            try {
+                final Resources r = getResourcesForApplication(appInfo);
+                final Drawable dr = r.getDrawable(resId, null);
+                if (dr != null) {
+                    putCachedIcon(name, dr);
+                }
+
+                if (false) {
+                    RuntimeException e = new RuntimeException("here");
+                    e.fillInStackTrace();
+                    Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resId)
+                                    + " from package " + packageName
+                                    + ": app scale=" + r.getCompatibilityInfo().applicationScale
+                                    + ", caller scale=" + mContext.getResources()
+                                    .getCompatibilityInfo().applicationScale,
+                            e);
+                }
+                if (DEBUG_ICONS)
+                    Log.v(TAG, "Getting drawable 0x"
+                            + Integer.toHexString(resId) + " from " + r
+                            + ": " + dr);
+            } catch (NameNotFoundException e) {
+                Log.w("PackageManager", "Failure retrieving resources for "
+                        + appInfo.packageName);
+            } catch (Resources.NotFoundException e) {
+                Log.w("PackageManager", "Failure retrieving resources for "
+                        + appInfo.packageName + ": " + e.getMessage());
+            } catch (Exception e) {
+                // If an exception was thrown, fall through to return
+                // default icon.
+                Log.w("PackageManager", "Failure retrieving icon 0x"
+                        + Integer.toHexString(resId) + " in package "
+                        + packageName, e);
             }
-            if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
-                                   + Integer.toHexString(resid) + " from " + r
-                                   + ": " + dr);
-            putCachedIcon(name, dr);
-            return dr;
-        } catch (NameNotFoundException e) {
-            Log.w("PackageManager", "Failure retrieving resources for "
-                  + appInfo.packageName);
-        } catch (Resources.NotFoundException e) {
-            Log.w("PackageManager", "Failure retrieving resources for "
-                  + appInfo.packageName + ": " + e.getMessage());
-        } catch (RuntimeException e) {
-            // If an exception was thrown, fall through to return
-            // default icon.
-            Log.w("PackageManager", "Failure retrieving icon 0x"
-                  + Integer.toHexString(resid) + " in package "
-                  + packageName, e);
         }
+
         return null;
     }
 
@@ -923,19 +936,21 @@
         return label;
     }
 
-    @Override public Resources getResourcesForActivity(
-        ComponentName activityName) throws NameNotFoundException {
+    @Override
+    public Resources getResourcesForActivity(ComponentName activityName)
+            throws NameNotFoundException {
         return getResourcesForApplication(
             getActivityInfo(activityName, sDefaultFlags).applicationInfo);
     }
 
-    @Override public Resources getResourcesForApplication(
-        ApplicationInfo app) throws NameNotFoundException {
+    @Override
+    public Resources getResourcesForApplication(@NonNull ApplicationInfo app)
+            throws NameNotFoundException {
         if (app.packageName.equals("system")) {
             return mContext.mMainThread.getSystemContext().getResources();
         }
         final boolean sameUid = (app.uid == Process.myUid());
-        Resources r = mContext.mMainThread.getTopLevelResources(
+        final Resources r = mContext.mMainThread.getTopLevelResources(
                 sameUid ? app.sourceDir : app.publicSourceDir,
                 sameUid ? app.splitSourceDirs : app.splitPublicSourceDirs,
                 app.resourceDirs, app.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
@@ -946,8 +961,9 @@
         throw new NameNotFoundException("Unable to open " + app.publicSourceDir);
     }
 
-    @Override public Resources getResourcesForApplication(
-        String appPackageName) throws NameNotFoundException {
+    @Override
+    public Resources getResourcesForApplication(String appPackageName)
+            throws NameNotFoundException {
         return getResourcesForApplication(
             getApplicationInfo(appPackageName, sDefaultFlags));
     }
@@ -999,13 +1015,14 @@
         mPM = pm;
     }
 
-    private Drawable getCachedIcon(ResourceName name) {
+    @Nullable
+    private Drawable getCachedIcon(@NonNull ResourceName name) {
         synchronized (sSync) {
-            WeakReference<Drawable.ConstantState> wr = sIconCache.get(name);
+            final WeakReference<Drawable.ConstantState> wr = sIconCache.get(name);
             if (DEBUG_ICONS) Log.v(TAG, "Get cached weak drawable ref for "
                                    + name + ": " + wr);
             if (wr != null) {   // we have the activity
-                Drawable.ConstantState state = wr.get();
+                final Drawable.ConstantState state = wr.get();
                 if (state != null) {
                     if (DEBUG_ICONS) {
                         Log.v(TAG, "Get cached drawable state for " + name + ": " + state);
@@ -1025,9 +1042,9 @@
         return null;
     }
 
-    private void putCachedIcon(ResourceName name, Drawable dr) {
+    private void putCachedIcon(@NonNull ResourceName name, @NonNull Drawable dr) {
         synchronized (sSync) {
-            sIconCache.put(name, new WeakReference<Drawable.ConstantState>(dr.getConstantState()));
+            sIconCache.put(name, new WeakReference<>(dr.getConstantState()));
             if (DEBUG_ICONS) Log.v(TAG, "Added cached drawable state for " + name + ": " + dr);
         }
     }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 4a1d6ff..59de281 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -262,7 +262,11 @@
 
     public void enterSafeMode() throws RemoteException;
     
-    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg)
+    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag)
+            throws RemoteException;
+    public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag)
+            throws RemoteException;
+    public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag)
             throws RemoteException;
 
     public boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;
@@ -490,6 +494,8 @@
             throws RemoteException;
     public void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;
 
+    public int getPackageProcessState(String packageName) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -825,4 +831,7 @@
     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;
+    int NOTE_ALARM_START_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+291;
+    int NOTE_ALARM_FINISH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+292;
+    int GET_PACKAGE_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+293;
 }
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index ddd21e6..56cd53e 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -253,6 +253,32 @@
     }
 
     /**
+     * Returns whether the device is secured with a PIN, pattern or
+     * password.
+     *
+     * @return true if a PIN, pattern or password was set.
+     */
+    public boolean isDeviceSecure() {
+        return isDeviceSecure(UserHandle.getCallingUserId());
+    }
+
+    /**
+     * Returns whether the device is secured with a PIN, pattern or
+     * password.
+     *
+     * @param userId the user for which the secure state should be reported.
+     * @return true if a PIN, pattern or password was set.
+     * @hide
+     */
+    public boolean isDeviceSecure(int userId) {
+        try {
+            return mTrustManager.isDeviceSecure(userId);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD}
      * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED}
      * instead; this allows you to seamlessly hide the keyguard as your application
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 88b1f2d..a0a6c4c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -754,6 +754,14 @@
     public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 0x0002;
 
     /**
+     * Broadcast action: notify that a new local OTA policy has been set by the device owner.
+     * The new policy can be retrieved by {@link #getOtaPolicy()}.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_OTA_POLICY_CHANGED = "android.app.action.OTA_POLICY_CHANGED";
+
+
+    /**
      * Return true if the given administrator component is currently
      * active (enabled) in the system.
      */
@@ -3254,6 +3262,73 @@
     }
 
     /**
+     * Called by a profile owner of a managed profile to set whether bluetooth
+     * devices can access enterprise contacts.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a
+     * security exception will be thrown.
+     * <p>
+     * This API works on managed profile only.
+     *
+     * @param who Which {@link DeviceAdminReceiver} this request is associated
+     *            with.
+     * @param disabled If true, bluetooth devices cannot access enterprise
+     *            contacts.
+     */
+    public void setBluetoothContactSharingDisabled(ComponentName who, boolean disabled) {
+        if (mService != null) {
+            try {
+                mService.setBluetoothContactSharingDisabled(who, disabled);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+    }
+
+    /**
+     * Called by a profile owner of a managed profile to determine whether or
+     * not Bluetooth devices cannot access enterprise contacts.
+     * <p>
+     * The calling device admin must be a profile owner. If it is not, a
+     * security exception will be thrown.
+     * <p>
+     * This API works on managed profile only.
+     *
+     * @param who Which {@link DeviceAdminReceiver} this request is associated
+     *            with.
+     */
+    public boolean getBluetoothContactSharingDisabled(ComponentName who) {
+        if (mService != null) {
+            try {
+                return mService.getBluetoothContactSharingDisabled(who);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Determine whether or not Bluetooth devices cannot access contacts.
+     * <p>
+     * This API works on managed profile UserHandle only.
+     *
+     * @param userHandle The user for whom to check the caller-id permission
+     * @hide
+     */
+    public boolean getBluetoothContactSharingDisabled(UserHandle userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getBluetoothContactSharingDisabledForUser(userHandle
+                        .getIdentifier());
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed talking with device policy service", e);
+            }
+        }
+        return true;
+    }
+
+    /**
      * Called by the profile owner of a managed profile so that some intents sent in the managed
      * profile can also be resolved in the parent, or vice versa.
      * Only activity intents are supported.
@@ -4067,4 +4142,72 @@
             Log.w(TAG, "Could not send device initializer status", re);
         }
     }
+
+    /*
+     * Called by device owners to set a local OTA update policy. When a new OTA policy is set,
+     * {@link #ACTION_OTA_POLICY_CHANGED} is broadcasted.
+     *
+     * @param who Which {@link DeviceAdminReceiver} this request is associated with. All components
+     * in the device owner package can set OTA policies and the most recent policy takes effect.
+     * @param policy the new OTA policy, or null to clear the current policy.
+     * @see OtaPolicy
+     */
+    public void setOtaPolicy(ComponentName who, OtaPolicy policy) {
+        if (mService != null) {
+            try {
+                if (policy != null) {
+                    mService.setOtaPolicy(who, policy.getPolicyBundle());
+                } else {
+                    mService.setOtaPolicy(who, null);
+                }
+            } catch (RemoteException re) {
+                Log.w(TAG, "Error calling setOtaPolicy", re);
+            }
+        }
+    }
+
+    /**
+     * Retrieve a local OTA update policy set previously by {@link #setOtaPolicy}.
+     *
+     * @return The current OTA policy object, or null if no policy is set or the system does not
+     * support managed OTA.
+     */
+    public OtaPolicy getOtaPolicy() {
+        if (mService != null) {
+            try {
+                PersistableBundle bundle = mService.getOtaPolicy();
+                if (bundle != null) {
+                    return new OtaPolicy(bundle);
+                } else {
+                    return null;
+                }
+            } catch (RemoteException re) {
+                Log.w(TAG, "Error calling getOtaPolicy", re);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Called by a device owner to disable the keyguard altogether.
+     *
+     * <p>Setting the keyguard to disabled has the same effect as choosing "None" as the screen
+     * lock type. However, this call has no effect if a password, pin or pattern is currently set.
+     * If a password, pin or pattern is set after the keyguard was disabled, the keyguard stops
+     * being disabled.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param enabled New state of the keyguard.
+     *
+     * @return {@code false} if attempting to disable the keyguard while a lock password was in
+     * place. {@code true} otherwise."
+     */
+    public boolean setKeyguardEnabledState(ComponentName admin, boolean enabled) {
+        try {
+            return mService.setKeyguardEnabledState(admin, enabled);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Failed talking with device policy service", re);
+            return false;
+        }
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 75b97a8..131b99c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -191,6 +191,10 @@
     boolean getCrossProfileCallerIdDisabledForUser(int userId);
     void startManagedQuickContact(String lookupKey, long contactId, in Intent originalIntent);
 
+    void setBluetoothContactSharingDisabled(in ComponentName who, boolean disabled);
+    boolean getBluetoothContactSharingDisabled(in ComponentName who);
+    boolean getBluetoothContactSharingDisabledForUser(int userId);
+
     void setTrustAgentConfiguration(in ComponentName admin, in ComponentName agent,
             in PersistableBundle args);
     List<PersistableBundle> getTrustAgentConfiguration(in ComponentName admin,
@@ -215,4 +219,8 @@
     void setUserIcon(in ComponentName admin, in Bitmap icon);
 
     void sendDeviceInitializerStatus(int statusCode, String description);
+    void setOtaPolicy(in ComponentName who, in PersistableBundle policy);
+    PersistableBundle getOtaPolicy();
+
+    boolean setKeyguardEnabledState(in ComponentName admin, boolean enabled);
 }
diff --git a/core/java/android/app/admin/OtaPolicy.java b/core/java/android/app/admin/OtaPolicy.java
new file mode 100644
index 0000000..98581a7
--- /dev/null
+++ b/core/java/android/app/admin/OtaPolicy.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.admin;
+
+import android.annotation.IntDef;
+import android.os.PersistableBundle;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A class that represents a local OTA policy set by the device owner.
+ *
+ * @see DevicePolicyManager#setOtaPolicy
+ * @see DevicePolicyManager#getOtaPolicy
+ */
+public class OtaPolicy {
+
+    /** @hide */
+    @IntDef({
+        TYPE_INSTALL_AUTOMATIC,
+        TYPE_INSTALL_WINDOWED,
+        TYPE_POSTPONE})
+    @Retention(RetentionPolicy.SOURCE)
+    @interface OtaPolicyType {}
+
+    /**
+     * Install OTA update automatically as soon as one is available.
+     */
+    public static final int TYPE_INSTALL_AUTOMATIC = 1;
+
+    /**
+     * Install OTA update automatically within a daily maintenance window, for a maximum of two-week
+     * period. After that period the OTA will be installed automatically.
+     */
+    public static final int TYPE_INSTALL_WINDOWED = 2;
+
+    /**
+     * Incoming OTA will be blocked for a maximum of two weeks, after which it will be installed
+     * automatically.
+     */
+    public static final int TYPE_POSTPONE = 3;
+
+    private static final String KEY_POLICY_TYPE = "policy_type";
+    private static final String KEY_INSTALL_WINDOW_START = "install_window_start";
+    private static final String KEY_INSTALL_WINDOW_END = "install_window_end";
+
+    private PersistableBundle mPolicy;
+
+    public  OtaPolicy() {
+        mPolicy = new PersistableBundle();
+    }
+
+    /**
+     * Construct an OtaPolicy object from a bundle.
+     * @hide
+     */
+    public OtaPolicy(PersistableBundle in) {
+        mPolicy = new PersistableBundle(in);
+    }
+
+    /**
+     * Retrieve the underlying bundle where the policy is stored.
+     * @hide
+     */
+    public PersistableBundle getPolicyBundle() {
+        return new PersistableBundle(mPolicy);
+    }
+
+    /**
+     * Set the OTA policy to: install OTA update automatically as soon as one is available.
+     */
+    public void setAutomaticInstallPolicy() {
+        mPolicy.clear();
+        mPolicy.putInt(KEY_POLICY_TYPE, TYPE_INSTALL_AUTOMATIC);
+    }
+
+    /**
+     * Set the OTA policy to: new OTA update will only be installed automatically when the system
+     * clock is inside a daily maintenance window. If the start and end times are the same, the
+     * window is considered to include the WHOLE 24 hours, that is, OTAs can install at any time. If
+     * the given window in invalid, a {@link OtaPolicy.InvalidWindowException} will be thrown. If
+     * start time is later than end time, the window is considered spanning midnight, i.e. end time
+     * donates a time on the next day. The maintenance window will last for two weeks, after which
+     * the OTA will be installed automatically.
+     *
+     * @param startTime the start of the maintenance window, measured as the number of minutes from
+     * midnight in the device's local time. Must be in the range of [0, 1440).
+     * @param endTime the end of the maintenance window, measured as the number of minutes from
+     * midnight in the device's local time. Must be in the range of [0, 1440).
+     */
+    public void setWindowedInstallPolicy(int startTime, int endTime) throws InvalidWindowException{
+        if (startTime < 0 || startTime >= 1440 || endTime < 0 || endTime >= 1440) {
+            throw new InvalidWindowException("startTime and endTime must be inside [0, 1440)");
+        }
+        mPolicy.clear();
+        mPolicy.putInt(KEY_POLICY_TYPE, TYPE_INSTALL_WINDOWED);
+        mPolicy.putInt(KEY_INSTALL_WINDOW_START, startTime);
+        mPolicy.putInt(KEY_INSTALL_WINDOW_END, endTime);
+    }
+
+    /**
+     * Set the OTA policy to: block installation for a maximum period of two weeks. After the
+     * block expires the OTA will be installed automatically.
+     */
+    public void setPostponeInstallPolicy() {
+        mPolicy.clear();
+        mPolicy.putInt(KEY_POLICY_TYPE, TYPE_POSTPONE);
+    }
+
+    /**
+     * Returns the type of OTA policy.
+     *
+     * @return an integer, either one of {@link #TYPE_INSTALL_AUTOMATIC},
+     * {@link #TYPE_INSTALL_WINDOWED} and {@link #TYPE_POSTPONE}, or -1 if no policy has been set.
+     */
+    @OtaPolicyType
+    public int getPolicyType() {
+        return mPolicy.getInt(KEY_POLICY_TYPE, -1);
+    }
+
+    /**
+     * Get the start of the maintenance window.
+     *
+     * @return the start of the maintenance window measured as the number of minutes from midnight,
+     * or -1 if the policy does not have a maintenance window.
+     */
+    public int getInstallWindowStart() {
+        if (getPolicyType() == TYPE_INSTALL_WINDOWED) {
+            return mPolicy.getInt(KEY_INSTALL_WINDOW_START, -1);
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Get the end of the maintenance window.
+     *
+     * @return the end of the maintenance window measured as the number of minutes from midnight,
+     * or -1 if the policy does not have a maintenance window.
+     */
+    public int getInstallWindowEnd() {
+        if (getPolicyType() == TYPE_INSTALL_WINDOWED) {
+            return mPolicy.getInt(KEY_INSTALL_WINDOW_END, -1);
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return mPolicy.toString();
+    }
+
+    /**
+     * Exception thrown by {@link OtaPolicy#setWindowedInstallPolicy(int, int)} in case the
+     * specified window is invalid.
+     */
+    public static class InvalidWindowException extends Exception {
+        public InvalidWindowException(String reason) {
+            super(reason);
+        }
+    }
+}
+
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 68ea0aa..17cff5c 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -31,4 +31,5 @@
     void unregisterTrustListener(in ITrustListener trustListener);
     void reportKeyguardShowingChanged();
     boolean isDeviceLocked(int userId);
+    boolean isDeviceSecure(int userId);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index eea47b7..54fe786 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3311,6 +3311,14 @@
     public static final String EXTRA_INITIAL_INTENTS = "android.intent.extra.INITIAL_INTENTS";
 
     /**
+     * A Parcelable[] of {@link android.service.chooser.ChooserTarget ChooserTarget} objects
+     * as set with {@link #putExtra(String, Parcelable[])} representing additional app-specific
+     * targets to place at the front of the list of choices. Shown to the user with
+     * {@link #ACTION_CHOOSER}.
+     */
+    public static final String EXTRA_CHOOSER_TARGETS = "android.intent.extra.CHOOSER_TARGETS";
+
+    /**
      * A Bundle forming a mapping of potential target package names to different extras Bundles
      * to add to the default intent extras in {@link #EXTRA_INTENT} when used with
      * {@link #ACTION_CHOOSER}. Each key should be a package name. The package need not
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index ce83028..6b6f026 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -17,21 +17,31 @@
 package android.hardware.camera2;
 
 import android.os.Handler;
+import android.view.Surface;
 import java.util.List;
 
+
 /**
- * A configured capture session for a {@link CameraDevice}, used for capturing
- * images from the camera.
+ * A configured capture session for a {@link CameraDevice}, used for capturing images from the
+ * camera or reprocessing images captured from the camera in the same session previously.
  *
  * <p>A CameraCaptureSession is created by providing a set of target output surfaces to
- * {@link CameraDevice#createCaptureSession createCaptureSession}. Once created, the session is
- * active until a new session is created by the camera device, or the camera device is closed.</p>
+ * {@link CameraDevice#createCaptureSession createCaptureSession}, or by providing an
+ * {@link android.hardware.camera2.params.InputConfiguration} and a set of target output surfaces to
+ * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession} for a
+ * reprocessible capture session. Once created, the session is active until a new session is
+ * created by the camera device, or the camera device is closed.</p>
+ *
+ * <p>All capture sessions can be used for capturing images from the camera but only reprocessible
+ * capture sessions can reprocess images captured from the camera in the same session previously.
+ * </p>
  *
  * <p>Creating a session is an expensive operation and can take several hundred milliseconds, since
  * it requires configuring the camera device's internal pipelines and allocating memory buffers for
  * sending images to the desired targets. Therefore the setup is done asynchronously, and
- * {@link CameraDevice#createCaptureSession createCaptureSession} will send the ready-to-use
- * CameraCaptureSession to the provided listener's
+ * {@link CameraDevice#createCaptureSession createCaptureSession} and
+ * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession} will
+ * send the ready-to-use CameraCaptureSession to the provided listener's
  * {@link CameraCaptureSession.StateCallback#onConfigured onConfigured} callback. If configuration
  * cannot be completed, then the
  * {@link CameraCaptureSession.StateCallback#onConfigureFailed onConfigureFailed} is called, and the
@@ -77,6 +87,12 @@
      * {@link #setRepeatingBurst}, and will be processed as soon as the current
      * repeat/repeatBurst processing completes.</p>
      *
+     * <p>All capture sessions can be used for capturing images from the camera but only capture
+     * sessions created by
+     * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession}
+     * can submit reprocess capture requests. Submitting a reprocess request to a regular capture
+     * session will result in an {@link IllegalArgumentException}.</p>
+     *
      * @param request the settings for this capture
      * @param listener The callback object to notify once this request has been
      * processed. If null, no metadata will be produced for this capture,
@@ -94,7 +110,9 @@
      *                               was explicitly closed, a new session has been created
      *                               or the camera device has been closed.
      * @throws IllegalArgumentException if the request targets no Surfaces or Surfaces that are not
-     *                                  configured as outputs for this session. Or if the handler is
+     *                                  configured as outputs for this session. Or if a reprocess
+     *                                  capture request is submitted in a non-reprocessible capture
+     *                                  session. Or if the handler is
      *                                  null, the listener is not null, and the calling thread has
      *                                  no looper.
      *
@@ -102,6 +120,7 @@
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
      * @see #abortCaptures
+     * @see CameraDevice#createReprocessibleCaptureSession
      */
     public abstract int capture(CaptureRequest request, CaptureCallback listener, Handler handler)
             throws CameraAccessException;
@@ -121,6 +140,13 @@
      * {@link #capture} repeatedly is that this method guarantees that no
      * other requests will be interspersed with the burst.</p>
      *
+     * <p>All capture sessions can be used for capturing images from the camera but only capture
+     * sessions created by
+     * {@link CameraDevice#createReprocessibleCaptureSession createReprocessibleCaptureSession}
+     * can submit reprocess capture requests. The list of requests must all be capturing images from
+     * the camera or all be reprocess capture requests. Submitting a reprocess request to a regular
+     * capture session will result in an {@link IllegalArgumentException}.</p>
+     *
      * @param requests the list of settings for this burst capture
      * @param listener The callback object to notify each time one of the
      * requests in the burst has been processed. If null, no metadata will be
@@ -138,9 +164,13 @@
      * @throws IllegalStateException if this session is no longer active, either because the session
      *                               was explicitly closed, a new session has been created
      *                               or the camera device has been closed.
-     * @throws IllegalArgumentException If the requests target no Surfaces or Surfaces not currently
-     *                                  configured as outputs. Or if the handler is null, the
-     *                                  listener is not null, and the calling thread has no looper.
+     * @throws IllegalArgumentException If the requests target no Surfaces, or target Surfaces not
+     *                                  currently configured as outputs. Or if a reprocess
+     *                                  capture request is submitted in a non-reprocessible capture
+     *                                  session. Or if the list of requests contains both requests
+     *                                  to capture images from the camera and reprocess capture
+     *                                  requests. Or if the handler is null, the listener is not
+     *                                  null, and the calling thread has no looper.
      *
      * @see #capture
      * @see #setRepeatingRequest
@@ -175,6 +205,14 @@
      * in-progress burst will be completed before the new repeat request will be
      * used.</p>
      *
+     * <p>This method does not support reprocess capture requests because each reprocess
+     * {@link CaptureRequest} must be created from the {@link TotalCaptureResult} that matches
+     * the input image to be reprocessed. This is either the {@link TotalCaptureResult} of capture
+     * that is sent for reprocessing, or one of the {@link TotalCaptureResult TotalCaptureResults}
+     * of a set of captures, when data from the whole set is combined by the application into a
+     * single reprocess input image. The request must be capturing images from the camera. If a
+     * reprocess capture request is submitted, this method will throw IllegalArgumentException.</p>
+     *
      * @param request the request to repeat indefinitely
      * @param listener The callback object to notify every time the
      * request finishes processing. If null, no metadata will be
@@ -193,9 +231,10 @@
      *                               was explicitly closed, a new session has been created
      *                               or the camera device has been closed.
      * @throws IllegalArgumentException If the requests reference no Surfaces or Surfaces that are
-     *                                  not currently configured as outputs. Or if the handler is
-     *                                  null, the listener is not null, and the calling thread has
-     *                                  no looper. Or if no requests were passed in.
+     *                                  not currently configured as outputs. Or if the request is
+     *                                  a reprocess capture request. Or if the handler is null, the
+     *                                  listener is not null, and the calling thread has no looper.
+     *                                  Or if no requests were passed in.
      *
      * @see #capture
      * @see #captureBurst
@@ -235,6 +274,14 @@
      * in-progress burst will be completed before the new repeat burst will be
      * used.</p>
      *
+     * <p>This method does not support reprocess capture requests because each reprocess
+     * {@link CaptureRequest} must be created from the {@link TotalCaptureResult} that matches
+     * the input image to be reprocessed. This is either the {@link TotalCaptureResult} of capture
+     * that is sent for reprocessing, or one of the {@link TotalCaptureResult TotalCaptureResults}
+     * of a set of captures, when data from the whole set is combined by the application into a
+     * single reprocess input image. The request must be capturing images from the camera. If a
+     * reprocess capture request is submitted, this method will throw IllegalArgumentException.</p>
+     *
      * @param requests the list of requests to cycle through indefinitely
      * @param listener The callback object to notify each time one of the
      * requests in the repeating bursts has finished processing. If null, no
@@ -253,7 +300,8 @@
      *                               was explicitly closed, a new session has been created
      *                               or the camera device has been closed.
      * @throws IllegalArgumentException If the requests reference no Surfaces or Surfaces not
-     *                                  currently configured as outputs. Or if the handler is null,
+     *                                  currently configured as outputs. Or if one of the requests
+     *                                  is a reprocess capture request. Or if the handler is null,
      *                                  the listener is not null, and the calling thread has no
      *                                  looper. Or if no requests were passed in.
      *
@@ -298,9 +346,10 @@
      * request or a repeating burst is set, it will be cleared.</p>
      *
      * <p>This method is the fastest way to switch the camera device to a new session with
-     * {@link CameraDevice#createCaptureSession}, at the cost of discarding in-progress work. It
-     * must be called before the new session is created. Once all pending requests are either
-     * completed or thrown away, the {@link StateCallback#onReady} callback will be called,
+     * {@link CameraDevice#createCaptureSession} or
+     * {@link CameraDevice#createReprocessibleCaptureSession}, at the cost of discarding in-progress
+     * work. It must be called before the new session is created. Once all pending requests are
+     * either completed or thrown away, the {@link StateCallback#onReady} callback will be called,
      * if the session has not been closed. Otherwise, the {@link StateCallback#onClosed}
      * callback will be fired when a new session is created by the camera device.</p>
      *
@@ -321,10 +370,39 @@
      * @see #setRepeatingRequest
      * @see #setRepeatingBurst
      * @see CameraDevice#createCaptureSession
+     * @see CameraDevice#createReprocessibleCaptureSession
      */
     public abstract void abortCaptures() throws CameraAccessException;
 
     /**
+     * Return if the application can submit reprocess capture requests with this camera capture
+     * session.
+     *
+     * @return {@code true} if the application can submit reprocess capture requests with this
+     *         camera capture session. {@code false} otherwise.
+     *
+     * @see CameraDevice#createReprocessibleCaptureSession
+     */
+    public abstract boolean isReprocessible();
+
+    /**
+     * Get the input Surface associated with a reprocessible capture session.
+     *
+     * <p>Each reprocessible capture session has an input {@link Surface} where the reprocess
+     * capture requests get the input images from, rather than the camera device. The application
+     * can create a {@link android.media.ImageWriter} with this input {@link Surface} and use it to
+     * provide input images for reprocess capture requests.</p>
+     *
+     * @return The {@link Surface} where reprocessing capture requests get the input images from. If
+     *         this is not a reprocess capture session, {@code null} will be returned.
+     *
+     * @see CameraDevice#createReprocessibleCaptureSession
+     * @see android.media.ImageWriter
+     * @see android.media.ImageReader
+     */
+    public abstract Surface getInputSurface();
+
+    /**
      * Close this capture session asynchronously.
      *
      * <p>Closing a session frees up the target output Surfaces of the session for reuse with either
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index fd4cf3c..51b326b 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2;
 
+import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.os.Handler;
@@ -135,7 +136,7 @@
      *
      * <p>The active capture session determines the set of potential output Surfaces for
      * the camera device for each capture request. A given request may use all
-     * or a only some of the outputs. Once the CameraCaptureSession is created, requests can be
+     * or only some of the outputs. Once the CameraCaptureSession is created, requests can be
      * can be submitted with {@link CameraCaptureSession#capture capture},
      * {@link CameraCaptureSession#captureBurst captureBurst},
      * {@link CameraCaptureSession#setRepeatingRequest setRepeatingRequest}, or
@@ -393,6 +394,75 @@
             List<OutputConfiguration> outputConfigurations,
             CameraCaptureSession.StateCallback callback, Handler handler)
             throws CameraAccessException;
+    /**
+     * Create a new reprocessible camera capture session by providing the desired reprocessing
+     * input Surface configuration and the target output set of Surfaces to the camera device.
+     *
+     * <p>If a camera device supports YUV reprocessing
+     * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING}) or OPAQUE
+     * reprocessing
+     * ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_OPAQUE_REPROCESSING}), besides
+     * the capture session created via {@link #createCaptureSession}, the application can also
+     * create a reprocessible capture session to submit reprocess capture requests in addition to
+     * regular capture requests. A reprocess capture request takes the next available buffer from
+     * the session's input Surface, and sends it through the camera device's processing pipeline
+     * again, to produce buffers for the request's target output Surfaces. No new image data is
+     * captured for a reprocess request. However the input buffer provided by
+     * the application must be captured previously by the same camera device in the same session
+     * directly (e.g. for Zero-Shutter-Lag use case) or indirectly (e.g. combining multiple output
+     * images).</p>
+     *
+     * <p>The active reprocessible capture session determines an input {@link Surface} and the set
+     * of potential output Surfaces for the camera devices for each capture request. The application
+     * can use {@link #createCaptureRequest} to create regular capture requests to capture new
+     * images from the camera device, and use {@link #createReprocessCaptureRequest} to create
+     * reprocess capture requests to process buffers from the input {@link Surface}. A request may
+     * use all or only some of the outputs. All the output Surfaces in one capture request will come
+     * from the same source, either from a new capture by the camera device, or from the input
+     * Surface depending on if the request is a reprocess capture request.</p>
+     *
+     * <p>Input formats and sizes supported by the camera device can be queried via
+     * {@link StreamConfigurationMap#getInputFormats} and
+     * {@link StreamConfigurationMap#getInputSizes}. For each supported input format, the camera
+     * device supports a set of output formats and sizes for reprocessing that can be queried via
+     * {@link StreamConfigurationMap#getValidOutputFormatsForInput} and
+     * {@link StreamConfigurationMap#getOutputSizes}. While output Surfaces with formats that
+     * aren't valid reprocess output targets for the input configuration can be part of a session,
+     * they cannot be used as targets for a reprocessing request.</p>
+     *
+     * <p>Since the application cannot access {@link android.graphics.ImageFormat#PRIVATE} images
+     * directly, an output Surface created by {@link android.media.ImageReader#newOpaqueInstance}
+     * will be considered as intended to be used for reprocessing input and thus the
+     * {@link android.media.ImageReader} size must match one of the supported input sizes for
+     * {@link android.graphics.ImageFormat#PRIVATE} format. Otherwise, creating a reprocessible
+     * capture session will fail.</p>
+     *
+     * @param inputConfig The configuration for the input {@link Surface}
+     * @param outputs The new set of Surfaces that should be made available as
+     *                targets for captured image data.
+     * @param callback The callback to notify about the status of the new capture session.
+     * @param handler The handler on which the callback should be invoked, or {@code null} to use
+     *                the current thread's {@link android.os.Looper looper}.
+     *
+     * @throws IllegalArgumentException if the input configuration is null or not supported, the set
+     *                                  of output Surfaces do not meet the requirements, the
+     *                                  callback is null, or the handler is null but the current
+     *                                  thread has no looper.
+     * @throws CameraAccessException if the camera device is no longer connected or has
+     *                               encountered a fatal error
+     * @throws IllegalStateException if the camera device has been closed
+     *
+     * @see CameraCaptureSession
+     * @see StreamConfigurationMap#getInputFormats
+     * @see StreamConfigurationMap#getInputSizes
+     * @see StreamConfigurationMap#getValidOutputFormatsForInput
+     * @see StreamConfigurationMap#getOutputSizes
+     * @see android.media.ImageWriter
+     * @see android.media.ImageReader
+     */
+    public abstract void createReprocessibleCaptureSession(InputConfiguration inputConfig,
+            List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
+            throws CameraAccessException;
 
     /**
      * <p>Create a {@link CaptureRequest.Builder} for new capture requests,
@@ -423,6 +493,36 @@
             throws CameraAccessException;
 
     /**
+     * <p>Create a {@link CaptureRequest.Builder} for a new reprocess {@link CaptureRequest} from a
+     * {@link TotalCaptureResult}.
+     *
+     * <p>Each reprocess {@link CaptureRequest} processes one buffer from
+     * {@link CameraCaptureSession}'s input {@link Surface} to all output {@link Surface Surfaces}
+     * included in the reprocess capture request. The reprocess input images must be generated from
+     * one or multiple output images captured from the same camera device. The application can
+     * provide input images to camera device via
+     * {{@link android.media.ImageWriter#queueInputImage ImageWriter#queueInputImage}}.
+     * The application must use the capture result of one of those output images to create a
+     * reprocess capture request so that the camera device can use the information to achieve
+     * optimal reprocess image quality.
+     *
+     * @param inputResult The capture result of the output image or one of the output images used
+     *                       to generate the reprocess input image for this capture request.
+     *
+     * @throws IllegalArgumentException if inputResult is null.
+     * @throws CameraAccessException if the camera device is no longer connected or has
+     *                               encountered a fatal error
+     * @throws IllegalStateException if the camera device has been closed
+     *
+     * @see CaptureRequest.Builder
+     * @see TotalCaptureResult
+     * @see CameraDevice#createReprocessibleCaptureSession
+     * @see android.media.ImageWriter
+     */
+    public abstract CaptureRequest.Builder createReprocessCaptureRequest(
+            TotalCaptureResult inputResult) throws CameraAccessException;
+
+    /**
      * Close the connection to this camera device as quickly as possible.
      *
      * <p>Immediately after this call, all calls to the camera device or active session interface
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index b513379..1a00a05 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -148,7 +148,7 @@
      * new one provided.</p>
      *
      * <p>The first time a callback is registered, it is immediately called
-     * with the torch mode status of all currently known camera devices.</p>
+     * with the torch mode status of all currently known camera devices with a flash unit.</p>
      *
      * <p>Since this callback will be registered with the camera service, remember to unregister it
      * once it is no longer needed; otherwise the callback will continue to receive events
@@ -524,7 +524,7 @@
      * A callback for camera flash torch modes becoming unavailable, disabled, or enabled.
      *
      * <p>The torch mode becomes unavailable when the camera device it belongs to becomes
-     * unavailable or other camera resouces it needs become busy due to other higher priority
+     * unavailable or other camera resources it needs become busy due to other higher priority
      * camera activities. The torch mode becomes disabled when it was turned off or when the camera
      * device it belongs to is no longer in use and other camera resources it needs are no longer
      * busy. A camera's torch mode is turned off when an application calls {@link #setTorchMode} to
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index b8fb8e7..35727e8 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -157,6 +157,7 @@
 
     private final HashSet<Surface> mSurfaceSet;
     private final CameraMetadataNative mSettings;
+    private boolean mIsReprocess;
 
     private Object mUserTag;
 
@@ -168,6 +169,7 @@
     private CaptureRequest() {
         mSettings = new CameraMetadataNative();
         mSurfaceSet = new HashSet<Surface>();
+        mIsReprocess = false;
     }
 
     /**
@@ -179,6 +181,7 @@
     private CaptureRequest(CaptureRequest source) {
         mSettings = new CameraMetadataNative(source.mSettings);
         mSurfaceSet = (HashSet<Surface>) source.mSurfaceSet.clone();
+        mIsReprocess = source.mIsReprocess;
         mUserTag = source.mUserTag;
     }
 
@@ -187,9 +190,10 @@
      *
      * Used by the Builder to create a mutable CaptureRequest.
      */
-    private CaptureRequest(CameraMetadataNative settings) {
+    private CaptureRequest(CameraMetadataNative settings, boolean isReprocess) {
         mSettings = CameraMetadataNative.move(settings);
         mSurfaceSet = new HashSet<Surface>();
+        mIsReprocess = isReprocess;
     }
 
     /**
@@ -257,10 +261,27 @@
     }
 
     /**
+     * Determine if this is a reprocess capture request.
+     *
+     * <p>A reprocess capture request produces output images from an input buffer from the
+     * {@link CameraCaptureSession}'s input {@link Surface}. A reprocess capture request can be
+     * created by {@link CameraDevice#createReprocessCaptureRequest}.</p>
+     *
+     * @return {@code true} if this is a reprocess capture request. {@code false} if this is not a
+     * reprocess capture request.
+     *
+     * @see CameraDevice#createReprocessCaptureRequest
+     */
+    public boolean isReprocess() {
+        return mIsReprocess;
+    }
+
+    /**
      * Determine whether this CaptureRequest is equal to another CaptureRequest.
      *
      * <p>A request is considered equal to another is if it's set of key/values is equal, it's
-     * list of output surfaces is equal, and the user tag is equal.</p>
+     * list of output surfaces is equal, the user tag is equal, and the return values of
+     * isReprocess() are equal.</p>
      *
      * @param other Another instance of CaptureRequest.
      *
@@ -276,7 +297,8 @@
         return other != null
                 && Objects.equals(mUserTag, other.mUserTag)
                 && mSurfaceSet.equals(other.mSurfaceSet)
-                && mSettings.equals(other.mSettings);
+                && mSettings.equals(other.mSettings)
+                && mIsReprocess == other.mIsReprocess;
     }
 
     @Override
@@ -323,6 +345,8 @@
             Surface s = (Surface) p;
             mSurfaceSet.add(s);
         }
+
+        mIsReprocess = (in.readInt() == 0) ? false : true;
     }
 
     @Override
@@ -334,6 +358,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         mSettings.writeToParcel(dest, flags);
         dest.writeParcelableArray(mSurfaceSet.toArray(new Surface[mSurfaceSet.size()]), flags);
+        dest.writeInt(mIsReprocess ? 1 : 0);
     }
 
     /**
@@ -374,8 +399,8 @@
          *
          * @hide
          */
-        public Builder(CameraMetadataNative template) {
-            mRequest = new CaptureRequest(template);
+        public Builder(CameraMetadataNative template, boolean reprocess) {
+            mRequest = new CaptureRequest(template, reprocess);
         }
 
         /**
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d8f92e5..4134d28 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -295,11 +295,18 @@
      * <p>Whenever a request has been processed, regardless of failure or success,
      * it gets a unique frame number assigned to its future result/failure.</p>
      *
-     * <p>This value monotonically increments, starting with 0,
-     * for every new result or failure; and the scope is the lifetime of the
-     * {@link CameraDevice}.</p>
+     * <p>For the same type of request (capturing from the camera device or reprocessing), this
+     * value monotonically increments, starting with 0, for every new result or failure and the
+     * scope is the lifetime of the {@link CameraDevice}. Between different types of requests,
+     * the frame number may not monotonically increment. For example, the frame number of a newer
+     * reprocess result may be smaller than the frame number of an older result of capturing new
+     * images from the camera device, but the frame number of a newer reprocess result will never be
+     * smaller than the frame number of an older reprocess result.</p>
      *
      * @return The frame number
+     *
+     * @see CameraDevice#createCaptureRequest
+     * @see CameraDevice#createReprocessCaptureRequest
      */
     public long getFrameNumber() {
         return mFrameNumber;
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
index 01f2396..23bfa66 100644
--- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -16,11 +16,11 @@
 
 package android.hardware.camera2;
 
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.CaptureRequest;
-
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.utils.LongParcelable;
+import android.view.Surface;
 
 /** @hide */
 interface ICameraDeviceUser
@@ -68,6 +68,29 @@
     // non-negative value is the stream ID. negative value is status_t
     int createStream(in OutputConfiguration outputConfiguration);
 
+    /**
+     * Create an input stream
+     *
+     * <p>Create an input stream of width, height, and format</p>
+     *
+     * @param width Width of the input buffers
+     * @param height Height of the input buffers
+     * @param format Format of the input buffers. One of HAL_PIXEL_FORMAT_*.
+     *
+     * @return stream ID if it's a non-negative value. status_t if it's a negative value.
+     */
+    int createInputStream(int width, int height, int format);
+
+    /**
+     * Get the surface of the input stream.
+     *
+     * <p>It's valid to call this method only after a stream configuration is completed
+     * successfully and the stream configuration includes a input stream.</p>
+     *
+     * @param surface An output argument for the surface of the input stream buffer queue.
+     */
+    int getInputSurface(out Surface surface);
+
     int createDefaultRequest(int templateId, out CameraMetadataNative request);
 
     int getCameraInfo(out CameraMetadataNative info);
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index e87a2f8..fb5b13c 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -44,6 +44,8 @@
     private final int mId;
     private final String mIdString;
 
+    /** Input surface configured by native camera framework based on user-specified configuration */
+    private final Surface mInput;
     /** User-specified set of surfaces used as the configuration outputs */
     private final List<Surface> mOutputs;
     /**
@@ -85,7 +87,7 @@
      * There must be no pending actions
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
-    CameraCaptureSessionImpl(int id, List<Surface> outputs,
+    CameraCaptureSessionImpl(int id, Surface input, List<Surface> outputs,
             CameraCaptureSession.StateCallback callback, Handler stateHandler,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess) {
@@ -100,6 +102,7 @@
 
         // TODO: extra verification of outputs
         mOutputs = outputs;
+        mInput = input;
         mStateHandler = checkHandler(stateHandler);
         mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
 
@@ -145,8 +148,12 @@
             Handler handler) throws CameraAccessException {
         if (request == null) {
             throw new IllegalArgumentException("request must not be null");
+        } else if (request.isReprocess() && !isReprocessible()) {
+            throw new IllegalArgumentException("this capture session cannot handle reprocess " +
+                    "requests");
         }
 
+
         checkNotClosed();
 
         handler = checkHandler(handler, callback);
@@ -169,6 +176,19 @@
             throw new IllegalArgumentException("requests must have at least one element");
         }
 
+        boolean reprocess = requests.get(0).isReprocess();
+        if (reprocess && !isReprocessible()) {
+            throw new IllegalArgumentException("this capture session cannot handle reprocess " +
+                    "requests");
+        }
+
+        for (int i = 1; i < requests.size(); i++) {
+            if (requests.get(i).isReprocess() != reprocess) {
+                throw new IllegalArgumentException("cannot mix regular and reprocess capture " +
+                        " requests");
+            }
+        }
+
         checkNotClosed();
 
         handler = checkHandler(handler, callback);
@@ -188,8 +208,11 @@
             Handler handler) throws CameraAccessException {
         if (request == null) {
             throw new IllegalArgumentException("request must not be null");
+        } else if (request.isReprocess()) {
+            throw new IllegalArgumentException("repeating reprocess requests are not supported");
         }
 
+
         checkNotClosed();
 
         handler = checkHandler(handler, callback);
@@ -212,6 +235,13 @@
             throw new IllegalArgumentException("requests must have at least one element");
         }
 
+        for (CaptureRequest r : requests) {
+            if (r.isReprocess()) {
+                throw new IllegalArgumentException("repeating reprocess burst requests are not " +
+                        "supported");
+            }
+        }
+
         checkNotClosed();
 
         handler = checkHandler(handler, callback);
@@ -257,6 +287,16 @@
         // The next BUSY -> IDLE set of transitions will mark the end of the abort.
     }
 
+    @Override
+    public boolean isReprocessible() {
+        return mInput != null;
+    }
+
+    @Override
+    public Surface getInputSurface() {
+        return mInput;
+    }
+
     /**
      * Replace this session with another session.
      *
@@ -658,8 +698,8 @@
                     mUnconfigureDrainer.taskStarted();
 
                     try {
-                        mDeviceImpl
-                                .configureOutputsChecked(null); // begin transition to unconfigured
+                        // begin transition to unconfigured
+                        mDeviceImpl.configureStreamsChecked(null, null);
                     } catch (CameraAccessException e) {
                         // OK: do not throw checked exceptions.
                         Log.e(TAG, mIdString + "Exception while configuring outputs: ", e);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 38f8e39..91388c3 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -28,7 +28,10 @@
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.params.ReprocessFormatsMap;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.hardware.camera2.utils.CameraRuntimeException;
 import android.hardware.camera2.utils.LongParcelable;
@@ -37,6 +40,7 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.Size;
 import android.util.SparseArray;
 import android.view.Surface;
 
@@ -46,7 +50,8 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
-import java.util.TreeSet;
+import java.util.LinkedList;
+import java.util.TreeMap;
 
 /**
  * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate
@@ -78,9 +83,11 @@
 
     private int mRepeatingRequestId = REQUEST_ID_NONE;
     private final ArrayList<Integer> mRepeatingRequestIdDeletedList = new ArrayList<Integer>();
-    // Map stream IDs to Surfaces
+    // Map stream IDs to input/output configurations
+    private SimpleEntry<Integer, InputConfiguration> mConfiguredInput =
+            new SimpleEntry<>(REQUEST_ID_NONE, null);
     private final SparseArray<OutputConfiguration> mConfiguredOutputs =
-            new SparseArray<OutputConfiguration>();
+            new SparseArray<>();
 
     private final String mCameraId;
     private final CameraCharacteristics mCharacteristics;
@@ -320,38 +327,48 @@
         for (Surface s : outputs) {
             outputConfigs.add(new OutputConfiguration(s));
         }
-        configureOutputsChecked(outputConfigs);
+        configureStreamsChecked(/*inputConfig*/null, outputConfigs);
+
     }
 
     /**
-     * Attempt to configure the outputs; the device goes to idle and then configures the
-     * new outputs if possible.
+     * Attempt to configure the input and outputs; the device goes to idle and then configures the
+     * new input and outputs if possible.
      *
-     * <p>The configuration may gracefully fail, if there are too many outputs, if the formats
-     * are not supported, or if the sizes for that format is not supported. In this case this
-     * function will return {@code false} and the unconfigured callback will be fired.</p>
+     * <p>The configuration may gracefully fail, if input configuration is not supported,
+     * if there are too many outputs, if the formats are not supported, or if the sizes for that
+     * format is not supported. In this case this function will return {@code false} and the
+     * unconfigured callback will be fired.</p>
      *
-     * <p>If the configuration succeeds (with 1 or more outputs), then the idle callback is fired.
-     * Unconfiguring the device always fires the idle callback.</p>
+     * <p>If the configuration succeeds (with 1 or more outputs with or without an input),
+     * then the idle callback is fired. Unconfiguring the device always fires the idle callback.</p>
      *
+     * @param inputConfig input configuration or {@code null} for no input
      * @param outputs a list of one or more surfaces, or {@code null} to unconfigure
      * @return whether or not the configuration was successful
      *
      * @throws CameraAccessException if there were any unexpected problems during configuration
      */
-    public boolean configureOutputsChecked(List<OutputConfiguration> outputs)
-            throws CameraAccessException {
+    public boolean configureStreamsChecked(InputConfiguration inputConfig,
+            List<OutputConfiguration> outputs) throws CameraAccessException {
         // Treat a null input the same an empty list
         if (outputs == null) {
             outputs = new ArrayList<OutputConfiguration>();
         }
+        if (outputs.size() == 0 && inputConfig != null) {
+            throw new IllegalArgumentException("cannot configure an input stream without " +
+                    "any output streams");
+        }
+
+        checkInputConfiguration(inputConfig);
+
         boolean success = false;
 
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
             // Streams to create
             HashSet<OutputConfiguration> addSet = new HashSet<OutputConfiguration>(outputs);
-         // Streams to delete
+            // Streams to delete
             List<Integer> deleteList = new ArrayList<Integer>();
 
             // Determine which streams need to be created, which to be deleted
@@ -373,6 +390,24 @@
                 waitUntilIdle();
 
                 mRemoteDevice.beginConfigure();
+
+                // reconfigure the input stream if the input configuration is different.
+                InputConfiguration currentInputConfig = mConfiguredInput.getValue();
+                if (inputConfig != currentInputConfig &&
+                        (inputConfig == null || !inputConfig.equals(currentInputConfig))) {
+                    if (currentInputConfig != null) {
+                        mRemoteDevice.deleteStream(mConfiguredInput.getKey());
+                        mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
+                                REQUEST_ID_NONE, null);
+                    }
+                    if (inputConfig != null) {
+                        int streamId = mRemoteDevice.createInputStream(inputConfig.getWidth(),
+                                inputConfig.getHeight(), inputConfig.getFormat());
+                        mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(
+                                streamId, inputConfig);
+                    }
+                }
+
                 // Delete all streams first (to free up HW resources)
                 for (Integer streamId : deleteList) {
                     mRemoteDevice.deleteStream(streamId);
@@ -429,7 +464,7 @@
         for (Surface surface : outputs) {
             outConfigurations.add(new OutputConfiguration(surface));
         }
-        createCaptureSessionByOutputConfiguration(outConfigurations, callback, handler);
+        createCaptureSessionInternal(null, outConfigurations, callback, handler);
     }
 
     @Override
@@ -437,9 +472,39 @@
             List<OutputConfiguration> outputConfigurations,
             CameraCaptureSession.StateCallback callback, Handler handler)
             throws CameraAccessException {
+        if (DEBUG) {
+            Log.d(TAG, "createCaptureSessionByOutputConfiguration");
+        }
+
+        createCaptureSessionInternal(null, outputConfigurations, callback, handler);
+    }
+
+    @Override
+    public void createReprocessibleCaptureSession(InputConfiguration inputConfig,
+            List<Surface> outputs, CameraCaptureSession.StateCallback callback, Handler handler)
+            throws CameraAccessException {
+        if (DEBUG) {
+            Log.d(TAG, "createReprocessibleCaptureSession");
+        }
+
+        if (inputConfig == null) {
+            throw new IllegalArgumentException("inputConfig cannot be null when creating a " +
+                    "reprocessible capture session");
+        }
+        List<OutputConfiguration> outConfigurations = new ArrayList<>(outputs.size());
+        for (Surface surface : outputs) {
+            outConfigurations.add(new OutputConfiguration(surface));
+        }
+        createCaptureSessionInternal(inputConfig, outConfigurations, callback, handler);
+    }
+
+    private void createCaptureSessionInternal(InputConfiguration inputConfig,
+            List<OutputConfiguration> outputConfigurations,
+            CameraCaptureSession.StateCallback callback, Handler handler)
+            throws CameraAccessException {
         synchronized(mInterfaceLock) {
             if (DEBUG) {
-                Log.d(TAG, "createCaptureSession");
+                Log.d(TAG, "createCaptureSessionInternal");
             }
 
             checkIfCameraClosedOrInError();
@@ -453,15 +518,24 @@
             // TODO: dont block for this
             boolean configureSuccess = true;
             CameraAccessException pendingException = null;
+            Surface input = null;
             try {
-                // configure outputs and then block until IDLE
-                configureSuccess = configureOutputsChecked(outputConfigurations);
+                 // configure streams and then block until IDLE
+                configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations);
+                if (inputConfig != null) {
+                    input = new Surface();
+                    mRemoteDevice.getInputSurface(/*out*/input);
+                }
             } catch (CameraAccessException e) {
                 configureSuccess = false;
                 pendingException = e;
+                input = null;
                 if (DEBUG) {
                     Log.v(TAG, "createCaptureSession - failed with exception ", e);
                 }
+            } catch (RemoteException e) {
+                // impossible
+                return;
             }
 
             List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
@@ -470,7 +544,7 @@
             }
             // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
             CameraCaptureSessionImpl newSession =
-                    new CameraCaptureSessionImpl(mNextSessionId++,
+                    new CameraCaptureSessionImpl(mNextSessionId++, input,
                             outSurfaces, callback, handler, this, mDeviceHandler,
                             configureSuccess);
 
@@ -512,12 +586,25 @@
             }
 
             CaptureRequest.Builder builder =
-                    new CaptureRequest.Builder(templatedRequest);
+                    new CaptureRequest.Builder(templatedRequest, /*reprocess*/false);
 
             return builder;
         }
     }
 
+    @Override
+    public CaptureRequest.Builder createReprocessCaptureRequest(TotalCaptureResult inputResult)
+            throws CameraAccessException {
+        synchronized(mInterfaceLock) {
+            checkIfCameraClosedOrInError();
+
+            CameraMetadataNative resultMetadata = new
+                    CameraMetadataNative(inputResult.getNativeCopy());
+
+            return new CaptureRequest.Builder(resultMetadata, /*reprocess*/true);
+        }
+    }
+
     public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
             throws CameraAccessException {
         if (DEBUG) {
@@ -810,6 +897,40 @@
         }
     }
 
+    private void checkInputConfiguration(InputConfiguration inputConfig) {
+        if (inputConfig != null) {
+            StreamConfigurationMap configMap = mCharacteristics.get(
+                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+
+            int[] inputFormats = configMap.getInputFormats();
+            boolean validFormat = false;
+            for (int format : inputFormats) {
+                if (format == inputConfig.getFormat()) {
+                    validFormat = true;
+                }
+            }
+
+            if (validFormat == false) {
+                throw new IllegalArgumentException("input format " + inputConfig.getFormat() +
+                        " is not valid");
+            }
+
+            boolean validSize = false;
+            Size[] inputSizes = configMap.getInputSizes(inputConfig.getFormat());
+            for (Size s : inputSizes) {
+                if (inputConfig.getWidth() == s.getWidth() &&
+                        inputConfig.getHeight() == s.getHeight()) {
+                    validSize = true;
+                }
+            }
+
+            if (validSize == false) {
+                throw new IllegalArgumentException("input size " + inputConfig.getWidth() + "x" +
+                        inputConfig.getHeight() + " is not valid");
+            }
+        }
+    }
+
     /**
      * <p>A callback for tracking the progress of a {@link CaptureRequest}
      * submitted to the camera device.</p>
@@ -996,19 +1117,46 @@
     public class FrameNumberTracker {
 
         private long mCompletedFrameNumber = -1;
-        private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>();
+        private long mCompletedReprocessFrameNumber = -1;
+        /** the skipped frame numbers that belong to regular results */
+        private final LinkedList<Long> mSkippedRegularFrameNumbers = new LinkedList<Long>();
+        /** the skipped frame numbers that belong to reprocess results */
+        private final LinkedList<Long> mSkippedReprocessFrameNumbers = new LinkedList<Long>();
+        /** frame number -> is reprocess */
+        private final TreeMap<Long, Boolean> mFutureErrorMap = new TreeMap<Long, Boolean>();
         /** Map frame numbers to list of partial results */
         private final HashMap<Long, List<CaptureResult>> mPartialResults = new HashMap<>();
 
         private void update() {
-            Iterator<Long> iter = mFutureErrorSet.iterator();
+            Iterator iter = mFutureErrorMap.entrySet().iterator();
             while (iter.hasNext()) {
-                long errorFrameNumber = iter.next();
-                if (errorFrameNumber == mCompletedFrameNumber + 1) {
-                    mCompletedFrameNumber++;
-                    iter.remove();
+                TreeMap.Entry pair = (TreeMap.Entry)iter.next();
+                Long errorFrameNumber = (Long)pair.getKey();
+                Boolean reprocess = (Boolean)pair.getValue();
+                Boolean removeError = true;
+                if (reprocess) {
+                    if (errorFrameNumber == mCompletedReprocessFrameNumber + 1) {
+                        mCompletedReprocessFrameNumber = errorFrameNumber;
+                    } else if (mSkippedReprocessFrameNumbers.isEmpty() != true &&
+                            errorFrameNumber == mSkippedReprocessFrameNumbers.element()) {
+                        mCompletedReprocessFrameNumber = errorFrameNumber;
+                        mSkippedReprocessFrameNumbers.remove();
+                    } else {
+                        removeError = false;
+                    }
                 } else {
-                    break;
+                    if (errorFrameNumber == mCompletedFrameNumber + 1) {
+                        mCompletedFrameNumber = errorFrameNumber;
+                    } else if (mSkippedRegularFrameNumbers.isEmpty() != true &&
+                            errorFrameNumber == mSkippedRegularFrameNumbers.element()) {
+                        mCompletedFrameNumber = errorFrameNumber;
+                        mSkippedRegularFrameNumbers.remove();
+                    } else {
+                        removeError = false;
+                    }
+                }
+                if (removeError) {
+                    iter.remove();
                 }
             }
         }
@@ -1017,25 +1165,21 @@
          * This function is called every time when a result or an error is received.
          * @param frameNumber the frame number corresponding to the result or error
          * @param isError true if it is an error, false if it is not an error
+         * @param isReprocess true if it is a reprocess result, false if it is a regular result.
          */
-        public void updateTracker(long frameNumber, boolean isError) {
+        public void updateTracker(long frameNumber, boolean isError, boolean isReprocess) {
             if (isError) {
-                mFutureErrorSet.add(frameNumber);
+                mFutureErrorMap.put(frameNumber, isReprocess);
             } else {
-                /**
-                 * HAL cannot send an OnResultReceived for frame N unless it knows for
-                 * sure that all frames prior to N have either errored out or completed.
-                 * So if the current frame is not an error, then all previous frames
-                 * should have arrived. The following line checks whether this holds.
-                 */
-                if (frameNumber != mCompletedFrameNumber + 1) {
-                    Log.e(TAG, String.format(
-                            "result frame number %d comes out of order, should be %d + 1",
-                            frameNumber, mCompletedFrameNumber));
-                    // Continue on to set the completed frame number to this frame anyway,
-                    // to be robust to lower-level errors and allow for clean shutdowns.
+                try {
+                    if (isReprocess) {
+                        updateCompletedReprocessFrameNumber(frameNumber);
+                    } else {
+                        updateCompletedFrameNumber(frameNumber);
+                    }
+                } catch (IllegalArgumentException e) {
+                    Log.e(TAG, e.getMessage());
                 }
-                mCompletedFrameNumber = frameNumber;
             }
             update();
         }
@@ -1049,12 +1193,13 @@
          * @param frameNumber the frame number corresponding to the result
          * @param result the total or partial result
          * @param partial {@true} if the result is partial, {@code false} if total
+         * @param isReprocess true if it is a reprocess result, false if it is a regular result.
          */
-        public void updateTracker(long frameNumber, CaptureResult result, boolean partial) {
-
+        public void updateTracker(long frameNumber, CaptureResult result, boolean partial,
+                boolean isReprocess) {
             if (!partial) {
                 // Update the total result's frame status as being successful
-                updateTracker(frameNumber, /*isError*/false);
+                updateTracker(frameNumber, /*isError*/false, isReprocess);
                 // Don't keep a list of total results, we don't need to track them
                 return;
             }
@@ -1093,28 +1238,112 @@
             return mCompletedFrameNumber;
         }
 
+        public long getCompletedReprocessFrameNumber() {
+            return mCompletedReprocessFrameNumber;
+        }
+
+        /**
+         * Update the completed frame number for regular results.
+         *
+         * It validates that all previous frames have arrived except for reprocess frames.
+         *
+         * If there is a gap since previous regular frame number, assume the frames in the gap are
+         * reprocess frames and store them in the skipped reprocess frame number queue to check
+         * against when reprocess frames arrive.
+         */
+        private void updateCompletedFrameNumber(long frameNumber) throws IllegalArgumentException {
+            if (frameNumber <= mCompletedFrameNumber) {
+                throw new IllegalArgumentException("frame number " + frameNumber + " is a repeat");
+            } else if (frameNumber <= mCompletedReprocessFrameNumber) {
+                // if frame number is smaller than completed reprocess frame number,
+                // it must be the head of mSkippedRegularFrameNumbers
+                if (mSkippedRegularFrameNumbers.isEmpty() == true ||
+                        frameNumber < mSkippedRegularFrameNumbers.element()) {
+                    throw new IllegalArgumentException("frame number " + frameNumber +
+                            " is a repeat");
+                } else if (frameNumber > mSkippedRegularFrameNumbers.element()) {
+                    throw new IllegalArgumentException("frame number " + frameNumber +
+                            " comes out of order. Expecting " +
+                            mSkippedRegularFrameNumbers.element());
+                }
+                // frame number matches the head of the skipped frame number queue.
+                mSkippedRegularFrameNumbers.remove();
+            } else {
+                // there is a gap of unseen frame numbers which should belong to reprocess result
+                // put all the skipped frame numbers in the queue
+                for (long i = Math.max(mCompletedFrameNumber, mCompletedReprocessFrameNumber) + 1;
+                        i < frameNumber; i++) {
+                    mSkippedReprocessFrameNumbers.add(i);
+                }
+            }
+
+            mCompletedFrameNumber = frameNumber;
+        }
+
+        /**
+         * Update the completed frame number for reprocess results.
+         *
+         * It validates that all previous frames have arrived except for regular frames.
+         *
+         * If there is a gap since previous reprocess frame number, assume the frames in the gap are
+         * regular frames and store them in the skipped regular frame number queue to check
+         * against when regular frames arrive.
+         */
+        private void updateCompletedReprocessFrameNumber(long frameNumber)
+                throws IllegalArgumentException {
+            if (frameNumber < mCompletedReprocessFrameNumber) {
+                throw new IllegalArgumentException("frame number " + frameNumber + " is a repeat");
+            } else if (frameNumber < mCompletedFrameNumber) {
+                // if reprocess frame number is smaller than completed regular frame number,
+                // it must be the head of the skipped reprocess frame number queue.
+                if (mSkippedReprocessFrameNumbers.isEmpty() == true ||
+                        frameNumber < mSkippedReprocessFrameNumbers.element()) {
+                    throw new IllegalArgumentException("frame number " + frameNumber +
+                            " is a repeat");
+                } else if (frameNumber > mSkippedReprocessFrameNumbers.element()) {
+                    throw new IllegalArgumentException("frame number " + frameNumber +
+                            " comes out of order. Expecting " +
+                            mSkippedReprocessFrameNumbers.element());
+                }
+                // frame number matches the head of the skipped frame number queue.
+                mSkippedReprocessFrameNumbers.remove();
+            } else {
+                // put all the skipped frame numbers in the queue
+                for (long i = Math.max(mCompletedFrameNumber, mCompletedReprocessFrameNumber) + 1;
+                        i < frameNumber; i++) {
+                    mSkippedRegularFrameNumbers.add(i);
+                }
+            }
+            mCompletedReprocessFrameNumber = frameNumber;
+        }
     }
 
     private void checkAndFireSequenceComplete() {
         long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber();
+        long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber();
+        boolean isReprocess = false;
         Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator();
         while (iter.hasNext()) {
             final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next();
-            if (frameNumberRequestPair.getKey() <= completedFrameNumber) {
+            boolean sequenceCompleted = false;
+            final int requestId = frameNumberRequestPair.getValue();
+            final CaptureCallbackHolder holder;
+            synchronized(mInterfaceLock) {
+                if (mRemoteDevice == null) {
+                    Log.w(TAG, "Camera closed while checking sequences");
+                    return;
+                }
 
-                // remove request from mCaptureCallbackMap
-                final int requestId = frameNumberRequestPair.getValue();
-                final CaptureCallbackHolder holder;
-                synchronized(mInterfaceLock) {
-                    if (mRemoteDevice == null) {
-                        Log.w(TAG, "Camera closed while checking sequences");
-                        return;
-                    }
-
-                    int index = mCaptureCallbackMap.indexOfKey(requestId);
-                    holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index)
-                            : null;
-                    if (holder != null) {
+                int index = mCaptureCallbackMap.indexOfKey(requestId);
+                holder = (index >= 0) ?
+                        mCaptureCallbackMap.valueAt(index) : null;
+                if (holder != null) {
+                    isReprocess = holder.getRequest().isReprocess();
+                    // check if it's okay to remove request from mCaptureCallbackMap
+                    if ((isReprocess && frameNumberRequestPair.getKey() <=
+                            completedReprocessFrameNumber) || (!isReprocess &&
+                            frameNumberRequestPair.getKey() <= completedFrameNumber)) {
+                        sequenceCompleted = true;
                         mCaptureCallbackMap.removeAt(index);
                         if (DEBUG) {
                             Log.v(TAG, String.format(
@@ -1125,36 +1354,40 @@
                         }
                     }
                 }
+            }
+
+            // If no callback is registered for this requestId or sequence completed, remove it
+            // from the frame number->request pair because it's not needed anymore.
+            if (holder == null || sequenceCompleted) {
                 iter.remove();
+            }
 
-                // Call onCaptureSequenceCompleted
-                if (holder != null) {
-                    Runnable resultDispatch = new Runnable() {
-                        @Override
-                        public void run() {
-                            if (!CameraDeviceImpl.this.isClosed()){
-                                if (DEBUG) {
-                                    Log.d(TAG, String.format(
-                                            "fire sequence complete for request %d",
-                                            requestId));
-                                }
-
-                                long lastFrameNumber = frameNumberRequestPair.getKey();
-                                if (lastFrameNumber < Integer.MIN_VALUE
-                                        || lastFrameNumber > Integer.MAX_VALUE) {
-                                    throw new AssertionError(lastFrameNumber
-                                            + " cannot be cast to int");
-                                }
-                                holder.getCallback().onCaptureSequenceCompleted(
-                                    CameraDeviceImpl.this,
-                                    requestId,
-                                    lastFrameNumber);
+            // Call onCaptureSequenceCompleted
+            if (sequenceCompleted) {
+                Runnable resultDispatch = new Runnable() {
+                    @Override
+                    public void run() {
+                        if (!CameraDeviceImpl.this.isClosed()){
+                            if (DEBUG) {
+                                Log.d(TAG, String.format(
+                                        "fire sequence complete for request %d",
+                                        requestId));
                             }
-                        }
-                    };
-                    holder.getHandler().post(resultDispatch);
-                }
 
+                            long lastFrameNumber = frameNumberRequestPair.getKey();
+                            if (lastFrameNumber < Integer.MIN_VALUE
+                                    || lastFrameNumber > Integer.MAX_VALUE) {
+                                throw new AssertionError(lastFrameNumber
+                                        + " cannot be cast to int");
+                            }
+                            holder.getCallback().onCaptureSequenceCompleted(
+                                CameraDeviceImpl.this,
+                                requestId,
+                                lastFrameNumber);
+                        }
+                    }
+                };
+                holder.getHandler().post(resultDispatch);
             }
         }
     }
@@ -1319,9 +1552,11 @@
 
                 final CaptureCallbackHolder holder =
                         CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId);
+                final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
 
                 boolean isPartialResult =
                         (resultExtras.getPartialResultCount() < mTotalPartialCount);
+                boolean isReprocess = request.isReprocess();
 
                 // Check if we have a callback for this
                 if (holder == null) {
@@ -1331,7 +1566,8 @@
                                         + frameNumber);
                     }
 
-                    mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
+                    mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
+                            isReprocess);
 
                     return;
                 }
@@ -1343,11 +1579,11 @@
                                         + frameNumber);
                     }
 
-                    mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult);
+                    mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
+                            isReprocess);
                     return;
                 }
 
-                final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId());
 
                 Runnable resultDispatch = null;
 
@@ -1398,7 +1634,7 @@
                 holder.getHandler().post(resultDispatch);
 
                 // Collect the partials for a total result; or mark the frame as totally completed
-                mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult);
+                mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult, isReprocess);
 
                 // Fire onCaptureSequenceCompleted
                 if (!isPartialResult) {
@@ -1460,7 +1696,7 @@
             if (DEBUG) {
                 Log.v(TAG, String.format("got error frame %d", frameNumber));
             }
-            mFrameNumberTracker.updateTracker(frameNumber, /*error*/true);
+            mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess());
             checkAndFireSequenceComplete();
         }
 
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index 70f3463..4cd9414 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -530,6 +530,18 @@
     }
 
     @Override
+    public int createInputStream(int width, int height, int format) {
+        Log.e(TAG, "creating input stream is not supported on legacy devices");
+        return CameraBinderDecorator.INVALID_OPERATION;
+    }
+
+    @Override
+    public int getInputSurface(/*out*/ Surface surface) {
+        Log.e(TAG, "getting input surface is not supported on legacy devices");
+        return CameraBinderDecorator.INVALID_OPERATION;
+    }
+
+    @Override
     public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
         if (DEBUG) {
             Log.d(TAG, "createDefaultRequest called.");
diff --git a/core/java/android/hardware/camera2/params/InputConfiguration.java b/core/java/android/hardware/camera2/params/InputConfiguration.java
new file mode 100644
index 0000000..dea1c5c
--- /dev/null
+++ b/core/java/android/hardware/camera2/params/InputConfiguration.java
@@ -0,0 +1,115 @@
+/*
+ * 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.hardware.camera2.params;
+
+import android.hardware.camera2.utils.HashCodeHelpers;
+
+/**
+ * Immutable class to store an input configuration that is used to create a reprocessible capture
+ * session.
+ *
+ * @see CameraDevice#createReprocessibleCaptureSession
+ * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+ */
+public final class InputConfiguration {
+
+    private final int mWidth;
+    private final int mHeight;
+    private final int mFormat;
+
+    /**
+     * Create an input configration with the width, height, and user-defined format.
+     *
+     * <p>Images of an user-defined format are accessible by applications. Use
+     * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
+     * to query supported input formats</p>
+     *
+     * @param width Width of the input buffers.
+     * @param height Height of the input buffers.
+     * @param format Format of the input buffers. One of ImageFormat or PixelFormat constants.
+     *
+     * @see android.graphics.ImageFormat
+     * @see android.graphics.PixelFormat
+     * @see android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
+     */
+    public InputConfiguration(int width, int height, int format) {
+        mWidth = width;
+        mHeight = height;
+        mFormat = format;
+    }
+
+    /**
+     * Get the width of this input configration.
+     *
+     * @return width of this input configuration.
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * Get the height of this input configration.
+     *
+     * @return height of this input configuration.
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * Get the format of this input configration.
+     *
+     * @return format of this input configuration.
+     */
+    public int getFormat() {
+        return mFormat;
+    }
+
+    /**
+     * Check if this InputConfiguration is equal to another InputConfiguration.
+     *
+     * <p>Two input configurations are equal if and only if they have the same widths, heights, and
+     * formats.</p>
+     *
+     * @param obj the object to compare this instance with.
+     *
+     * @return {@code true} if the objects were equal, {@code false} otherwise.
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof InputConfiguration)) {
+            return false;
+        }
+
+        InputConfiguration otherInputConfig = (InputConfiguration) obj;
+
+        if (otherInputConfig.getWidth() == mWidth &&
+                otherInputConfig.getHeight() == mHeight &&
+                otherInputConfig.getFormat() == mFormat) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        return HashCodeHelpers.hashCode(mWidth, mHeight, mFormat);
+    }
+}
diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java
index 4696b2a..5d40e94 100644
--- a/core/java/android/hardware/location/GeofenceHardwareImpl.java
+++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java
@@ -53,6 +53,7 @@
 
     private IFusedGeofenceHardware mFusedService;
     private IGpsGeofenceHardware mGpsService;
+    private int mCapabilities;
 
     private int[] mSupportedMonitorTypes = new int[GeofenceHardware.NUM_MONITORS];
 
@@ -89,6 +90,9 @@
     private static final int RESOLUTION_LEVEL_COARSE = 2;
     private static final int RESOLUTION_LEVEL_FINE = 3;
 
+    // Capability constant corresponding to fused_location.h entry when geofencing supports GNNS.
+    private static final int CAPABILITY_GNSS = 1;
+
     public synchronized static GeofenceHardwareImpl getInstance(Context context) {
         if (sInstance == null) {
             sInstance = new GeofenceHardwareImpl(context);
@@ -141,7 +145,9 @@
     private void updateFusedHardwareAvailability() {
         boolean fusedSupported;
         try {
-            fusedSupported = (mFusedService != null ? mFusedService.isSupported() : false);
+            fusedSupported = (mFusedService != null
+                    ? mFusedService.isSupported() && (mCapabilities & CAPABILITY_GNSS) != 0
+                    : false);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException calling LocationManagerService");
             fusedSupported = false;
@@ -166,6 +172,11 @@
         }
     }
 
+    public void onCapabilities(int capabilities) {
+        mCapabilities = capabilities;
+        updateFusedHardwareAvailability();
+    }
+
     public void setFusedGeofenceHardware(IFusedGeofenceHardware service) {
         if(mFusedService == null) {
             mFusedService = service;
@@ -212,6 +223,20 @@
         }
     }
 
+    public int getCapabilitiesForMonitoringType(int monitoringType) {
+        switch (mSupportedMonitorTypes[monitoringType]) {
+            case GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE:
+                switch (monitoringType) {
+                    case GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE:
+                        return CAPABILITY_GNSS;
+                    case GeofenceHardware.MONITORING_TYPE_FUSED_HARDWARE:
+                        return mCapabilities;
+                }
+                break;
+        }
+        return 0;
+    }
+
     public boolean addCircularFence(
             int monitoringType,
             GeofenceHardwareRequestParcelable request,
diff --git a/core/java/android/hardware/location/GeofenceHardwareService.java b/core/java/android/hardware/location/GeofenceHardwareService.java
index 4816c5f..c0bcb27 100644
--- a/core/java/android/hardware/location/GeofenceHardwareService.java
+++ b/core/java/android/hardware/location/GeofenceHardwareService.java
@@ -65,14 +65,17 @@
     }
 
     private IBinder mBinder = new IGeofenceHardware.Stub() {
+        @Override
         public void setGpsGeofenceHardware(IGpsGeofenceHardware service) {
             mGeofenceHardwareImpl.setGpsHardwareGeofence(service);
         }
 
+        @Override
         public void setFusedGeofenceHardware(IFusedGeofenceHardware service) {
             mGeofenceHardwareImpl.setFusedGeofenceHardware(service);
         }
 
+        @Override
         public int[] getMonitoringTypes() {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
@@ -80,12 +83,15 @@
             return mGeofenceHardwareImpl.getMonitoringTypes();
         }
 
+        @Override
         public int getStatusOfMonitoringType(int monitoringType) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
 
             return mGeofenceHardwareImpl.getStatusOfMonitoringType(monitoringType);
         }
+
+        @Override
         public boolean addCircularFence(
                 int monitoringType,
                 GeofenceHardwareRequestParcelable request,
@@ -96,6 +102,7 @@
             return mGeofenceHardwareImpl.addCircularFence(monitoringType, request, callback);
         }
 
+        @Override
         public boolean removeGeofence(int id, int monitoringType) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
@@ -104,6 +111,7 @@
             return mGeofenceHardwareImpl.removeGeofence(id, monitoringType);
         }
 
+        @Override
         public boolean pauseGeofence(int id, int monitoringType) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
@@ -112,6 +120,7 @@
             return mGeofenceHardwareImpl.pauseGeofence(id, monitoringType);
         }
 
+        @Override
         public boolean resumeGeofence(int id, int monitoringType, int monitorTransitions) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                     "Location Hardware permission not granted to access hardware geofence");
@@ -120,6 +129,7 @@
             return mGeofenceHardwareImpl.resumeGeofence(id, monitoringType, monitorTransitions);
         }
 
+        @Override
         public boolean registerForMonitorStateChangeCallback(int monitoringType,
                 IGeofenceHardwareMonitorCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
@@ -130,6 +140,7 @@
                     callback);
         }
 
+        @Override
         public boolean unregisterForMonitorStateChangeCallback(int monitoringType,
                 IGeofenceHardwareMonitorCallback callback) {
             mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl
index 382c12c..3de766a 100644
--- a/core/java/android/hardware/location/IFusedLocationHardware.aidl
+++ b/core/java/android/hardware/location/IFusedLocationHardware.aidl
@@ -32,21 +32,21 @@
      *
      * @param eventSink     The sink to register.
      */
-    void registerSink(in IFusedLocationHardwareSink eventSink);
+    void registerSink(in IFusedLocationHardwareSink eventSink) = 0;
 
     /**
      * Unregisters a sink with the Location Hardware object.
      *
      * @param eventSink     The sink to unregister.
      */
-    void unregisterSink(in IFusedLocationHardwareSink eventSink);
+    void unregisterSink(in IFusedLocationHardwareSink eventSink) = 1;
 
     /**
      * Provides access to the batch size available in Hardware.
      *
      * @return The batch size the hardware supports.
      */
-    int getSupportedBatchSize();
+    int getSupportedBatchSize() = 2;
 
     /**
      * Requests the Hardware to start batching locations.
@@ -56,7 +56,7 @@
      *
      * @throws RuntimeException if the request Id exists.
      */
-    void startBatching(in int id, in FusedBatchOptions batchOptions);
+    void startBatching(in int id, in FusedBatchOptions batchOptions) = 3;
 
     /**
      * Requests the Hardware to stop batching for the given Id.
@@ -64,7 +64,7 @@
      * @param id    The request that needs to be stopped.
      * @throws RuntimeException if the request Id is unknown.
      */
-    void stopBatching(in int id);
+    void stopBatching(in int id) = 4;
 
     /**
      * Updates a batching operation in progress.
@@ -74,7 +74,7 @@
      *
      * @throws RuntimeException if the Id of the request is unknown.
      */
-    void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions);
+    void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions) = 5;
 
     /**
      * Requests the most recent locations available in Hardware.
@@ -83,14 +83,14 @@
      *
      * @param batchSizeRequested    The number of locations requested.
      */
-    void requestBatchOfLocations(in int batchSizeRequested);
+    void requestBatchOfLocations(in int batchSizeRequested) = 6;
 
     /**
      * Flags if the Hardware supports injection of diagnostic data.
      *
      * @return True if data injection is supported, false otherwise.
      */
-    boolean supportsDiagnosticDataInjection();
+    boolean supportsDiagnosticDataInjection() = 7;
 
     /**
      * Injects diagnostic data into the Hardware subsystem.
@@ -98,14 +98,14 @@
      * @param data  The data to inject.
      * @throws RuntimeException if injection is not supported.
      */
-    void injectDiagnosticData(in String data);
+    void injectDiagnosticData(in String data) = 8;
 
     /**
      * Flags if the Hardware supports injection of device context information.
      *
      * @return True if device context injection is supported, false otherwise.
      */
-    boolean supportsDeviceContextInjection();
+    boolean supportsDeviceContextInjection() = 9;
 
     /**
      * Injects device context information into the Hardware subsystem.
@@ -113,5 +113,12 @@
      * @param deviceEnabledContext  The context to inject.
      * @throws RuntimeException if injection is not supported.
      */
-    void injectDeviceContext(in int deviceEnabledContext);
+    void injectDeviceContext(in int deviceEnabledContext) = 10;
+
+    /**
+     * Requests all batched locations currently available in Hardware
+     * and clears the buffer.  Any subsequent calls will not return any
+     * of the locations returned in this call.
+     */
+    void flushBatchedLocations() = 11;
 }
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
index a11d8ab..c99cb0c 100644
--- a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -30,12 +30,24 @@
      *
      * @param locations     The batch of location information available.
      */
-    void onLocationAvailable(in Location[] locations);
+    void onLocationAvailable(in Location[] locations) = 0;
 
     /**
      * Event generated from FLP HAL to provide diagnostic data to the platform.
      *
      * @param data      The diagnostic data provided by FLP HAL.
      */
-    void onDiagnosticDataAvailable(in String data);
+    void onDiagnosticDataAvailable(in String data) = 1;
+
+    /**
+     * Event generated from FLP HAL to provide a mask of supported
+     * capabilities.  Should be called immediatly after init.
+     */
+    void onCapabilities(int capabilities) = 2;
+
+    /**
+     * Event generated from FLP HAL when the status of location batching
+     * changes (location is successful/unsuccessful).
+     */
+    void onStatusChanged(int status) = 3;
 }
\ No newline at end of file
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b268986..6b4f2d5 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -170,6 +170,21 @@
     }
 
     /**
+     * Determines whether the prefix contains the specified address.
+     *
+     * @param address An {@link InetAddress} to test.
+     * @return {@code true} if the prefix covers the given address.
+     */
+    public boolean contains(InetAddress address) {
+        byte[] addrBytes = (address == null) ? null : address.getAddress();
+        if (addrBytes == null || addrBytes.length != this.address.length) {
+            return false;
+        }
+        NetworkUtils.maskRawAddress(addrBytes, prefixLength);
+        return Arrays.equals(this.address, addrBytes);
+    }
+
+    /**
      * Returns a string representation of this {@code IpPrefix}.
      *
      * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index cfd20a0..90a2460 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -367,13 +367,7 @@
      * @return {@code true} if the destination and prefix length cover the given address.
      */
     public boolean matches(InetAddress destination) {
-        if (destination == null) return false;
-
-        // match the route destination and destination with prefix length
-        InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
-                mDestination.getPrefixLength());
-
-        return mDestination.getAddress().equals(dstNet);
+        return mDestination.contains(destination);
     }
 
     /**
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c7edb1a..7c5ddee 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1135,8 +1135,10 @@
         public static final int EVENT_PACKAGE_INSTALLED = 0x000c;
         // Event for a package being uninstalled.
         public static final int EVENT_PACKAGE_UNINSTALLED = 0x000d;
+        // Event for a package being uninstalled.
+        public static final int EVENT_ALARM = 0x000e;
         // Number of event types.
-        public static final int EVENT_COUNT = 0x000e;
+        public static final int EVENT_COUNT = 0x000f;
         // Mask to extract out only the type part of the event.
         public static final int EVENT_TYPE_MASK = ~(EVENT_FLAG_START|EVENT_FLAG_FINISH);
 
@@ -1158,6 +1160,8 @@
                 EVENT_USER_FOREGROUND | EVENT_FLAG_START;
         public static final int EVENT_USER_FOREGROUND_FINISH =
                 EVENT_USER_FOREGROUND | EVENT_FLAG_FINISH;
+        public static final int EVENT_ALARM_START = EVENT_ALARM | EVENT_FLAG_START;
+        public static final int EVENT_ALARM_FINISH = EVENT_ALARM | EVENT_FLAG_FINISH;
 
         // For CMD_EVENT.
         public int eventCode;
@@ -1789,12 +1793,12 @@
 
     public static final String[] HISTORY_EVENT_NAMES = new String[] {
             "null", "proc", "fg", "top", "sync", "wake_lock_in", "job", "user", "userfg", "conn",
-            "motion", "active", "pkginst", "pkgunin"
+            "motion", "active", "pkginst", "pkgunin", "alarm"
     };
 
     public static final String[] HISTORY_EVENT_CHECKIN_NAMES = new String[] {
             "Enl", "Epr", "Efg", "Etp", "Esy", "Ewl", "Ejb", "Eur", "Euf", "Ecn",
-            "Esm", "Eac", "Epi", "Epu"
+            "Esm", "Eac", "Epi", "Epu", "Eal"
     };
 
     /**
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 512e212..360e5c68 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -34,6 +34,7 @@
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
 
 import org.apache.harmony.dalvik.ddmc.Chunk;
 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
@@ -1101,6 +1102,95 @@
     }
 
     /**
+     * Returns the value of a particular runtime statistic or {@code null} if no
+     * such runtime statistic exists.
+     *
+     * <p>The following table lists the runtime statistics that the runtime supports.
+     * Note runtime statistics may be added or removed in a future API level.</p>
+     *
+     * <table>
+     *     <thead>
+     *         <tr>
+     *             <th>Runtime statistic name</th>
+     *             <th>Meaning</th>
+     *             <th>Example</th>
+     *             <th>Supported (API Levels)</th>
+     *         </tr>
+     *     </thead>
+     *     <tbody>
+     *         <tr>
+     *             <td>art.gc.gc-count</td>
+     *             <td>The number of garbage collection runs.</td>
+     *             <td>{@code 164}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.gc-time</td>
+     *             <td>The total duration of garbage collection runs in ms.</td>
+     *             <td>{@code 62364}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.bytes-allocated</td>
+     *             <td>The total number of bytes that the application allocated.</td>
+     *             <td>{@code 1463948408}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.bytes-freed</td>
+     *             <td>The total number of bytes that garbage collection reclaimed.</td>
+     *             <td>{@code 1313493084}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.blocking-gc-count</td>
+     *             <td>The number of blocking garbage collection runs.</td>
+     *             <td>{@code 2}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.blocking-gc-time</td>
+     *             <td>The total duration of blocking garbage collection runs in ms.</td>
+     *             <td>{@code 804}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.gc-count-rate-histogram</td>
+     *             <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+     *             <td>{@code 0:34503,1:45350,2:11281,3:8088,4:43,5:8}</td>
+     *             <td>23</td>
+     *         </tr>
+     *         <tr>
+     *             <td>art.gc.blocking-gc-count-rate-histogram</td>
+     *             <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+     *             <td>{@code 0:99269,1:1,2:1}</td>
+     *             <td>23</td>
+     *         </tr>
+     *     </tbody>
+     * </table>
+     *
+     * @param statName
+     *            the name of the runtime statistic to look up.
+     * @return the value of the specified runtime statistic or {@code null} if the
+     *         runtime statistic doesn't exist.
+     * @hide
+     */
+    public static String getRuntimeStat(String statName) {
+        return VMDebug.getRuntimeStat(statName);
+    }
+
+    /**
+     * Returns a map of the names/values of the runtime statistics
+     * that {@link #getRuntimeStat()} supports.
+     *
+     * @return a map of the names/values of the supported runtime statistics.
+     * @hide
+     */
+    public static Map<String, String> getRuntimeStats() {
+        return VMDebug.getRuntimeStats();
+    }
+
+    /**
      * Returns the size of the native heap.
      * @return The size of the native heap in bytes.
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3087e1d..109c23b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -889,6 +889,15 @@
             = "android.settings.ZEN_MODE_SCHEDULE_RULE_SETTINGS";
 
     /**
+     * Activity Action: Show Zen Mode external rule configuration settings.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_ZEN_MODE_EXTERNAL_RULE_SETTINGS
+            = "android.settings.ZEN_MODE_EXTERNAL_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
@@ -7708,6 +7717,13 @@
          */
         public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1",
                 "user_preferred_sub2","user_preferred_sub3"};
+
+        /**
+         * Whether to enable new contacts aggregator or not.
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String NEW_CONTACT_AGGREGATOR = "new_contact_aggregator";
     }
 
     /**
diff --git a/core/java/android/service/chooser/ChooserTarget.java b/core/java/android/service/chooser/ChooserTarget.java
index 7fd1d10..d21cc3c 100644
--- a/core/java/android/service/chooser/ChooserTarget.java
+++ b/core/java/android/service/chooser/ChooserTarget.java
@@ -17,6 +17,7 @@
 
 package android.service.chooser;
 
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
@@ -24,8 +25,10 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.graphics.Bitmap;
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.UserHandle;
 import android.util.Log;
 
 /**
@@ -55,6 +58,12 @@
     private IntentSender mIntentSender;
 
     /**
+     * A raw intent provided in lieu of an IntentSender. Will be filled in and sent
+     * by {@link #sendIntent(Context, Intent)}.
+     */
+    private Intent mIntent;
+
+    /**
      * The score given to this item. It can be normalized.
      */
     private float mScore;
@@ -135,6 +144,17 @@
         mIntentSender = intentSender;
     }
 
+    public ChooserTarget(CharSequence title, Bitmap icon, float score, Intent intent) {
+        mTitle = title;
+        mIcon = icon;
+        if (score > 1.f || score < 0.f) {
+            throw new IllegalArgumentException("Score " + score + " out of range; "
+                    + "must be between 0.0f and 1.0f");
+        }
+        mScore = score;
+        mIntent = intent;
+    }
+
     ChooserTarget(Parcel in) {
         mTitle = in.readCharSequence();
         if (in.readInt() != 0) {
@@ -144,6 +164,9 @@
         }
         mScore = in.readFloat();
         mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
+        if (in.readInt() != 0) {
+            mIntent = Intent.CREATOR.createFromParcel(in);
+        }
     }
 
     /**
@@ -179,6 +202,7 @@
 
     /**
      * Returns the raw IntentSender supplied by the ChooserTarget's creator.
+     * This may be null if the creator specified a regular Intent instead.
      *
      * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
      *
@@ -189,6 +213,18 @@
     }
 
     /**
+     * Returns the Intent supplied by the ChooserTarget's creator.
+     * This may be null if the creator specified an IntentSender or PendingIntent instead.
+     *
+     * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
+     *
+     * @return the Intent supplied by the ChooserTarget's creator
+     */
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    /**
      * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
      *
      * @param context the sending Context; generally the Activity presenting the chooser UI
@@ -200,18 +236,109 @@
             fillInIntent.migrateExtraStreamToClipData();
             fillInIntent.prepareToLeaveProcess();
         }
-        try {
-            mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
-            return true;
-        } catch (IntentSender.SendIntentException e) {
-            Log.e(TAG, "sendIntent " + this + " failed", e);
+        if (mIntentSender != null) {
+            try {
+                mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
+                return true;
+            } catch (IntentSender.SendIntentException e) {
+                Log.e(TAG, "sendIntent " + this + " failed", e);
+                return false;
+            }
+        } else if (mIntent != null) {
+            try {
+                final Intent toSend = new Intent(mIntent);
+                toSend.fillIn(fillInIntent, 0);
+                context.startActivity(toSend);
+                return true;
+            } catch (Exception e) {
+                Log.e(TAG, "sendIntent " + this + " failed", e);
+                return false;
+            }
+        } else {
+            Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
+            return false;
+        }
+    }
+
+    /**
+     * Same as {@link #sendIntent(Context, Intent)}, but offers a userId field to use
+     * for launching the {@link #getIntent() intent} using
+     * {@link Activity#startActivityAsCaller(Intent, Bundle, int)} if the
+     * {@link #getIntentSender() IntentSender} is not present. If the IntentSender is present,
+     * it will be invoked as usual with its own calling identity.
+     *
+     * @hide internal use only.
+     */
+    public boolean sendIntentAsCaller(Activity context, Intent fillInIntent, int userId) {
+        if (fillInIntent != null) {
+            fillInIntent.migrateExtraStreamToClipData();
+            fillInIntent.prepareToLeaveProcess();
+        }
+        if (mIntentSender != null) {
+            try {
+                mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
+                return true;
+            } catch (IntentSender.SendIntentException e) {
+                Log.e(TAG, "sendIntent " + this + " failed", e);
+                return false;
+            }
+        } else if (mIntent != null) {
+            try {
+                final Intent toSend = new Intent(mIntent);
+                toSend.fillIn(fillInIntent, 0);
+                context.startActivityAsCaller(toSend, null, userId);
+                return true;
+            } catch (Exception e) {
+                Log.e(TAG, "sendIntent " + this + " failed", e);
+                return false;
+            }
+        } else {
+            Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
+            return false;
+        }
+    }
+
+    /**
+     * The UserHandle is only used if we're launching a raw intent. The IntentSender will be
+     * launched with its associated identity.
+     *
+     * @hide Internal use only
+     */
+    public boolean sendIntentAsUser(Activity context, Intent fillInIntent, UserHandle user) {
+        if (fillInIntent != null) {
+            fillInIntent.migrateExtraStreamToClipData();
+            fillInIntent.prepareToLeaveProcess();
+        }
+        if (mIntentSender != null) {
+            try {
+                mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
+                return true;
+            } catch (IntentSender.SendIntentException e) {
+                Log.e(TAG, "sendIntent " + this + " failed", e);
+                return false;
+            }
+        } else if (mIntent != null) {
+            try {
+                final Intent toSend = new Intent(mIntent);
+                toSend.fillIn(fillInIntent, 0);
+                context.startActivityAsUser(toSend, user);
+                return true;
+            } catch (Exception e) {
+                Log.e(TAG, "sendIntent " + this + " failed", e);
+                return false;
+            }
+        } else {
+            Log.e(TAG, "sendIntent " + this + " failed - no IntentSender or Intent to send");
             return false;
         }
     }
 
     @Override
     public String toString() {
-        return "ChooserTarget{" + mIntentSender.getCreatorPackage() + "'" + mTitle
+        return "ChooserTarget{"
+                + (mIntentSender != null ? mIntentSender.getCreatorPackage() : mIntent)
+                + ", "
+                + "'" + mTitle
                 + "', " + mScore + "}";
     }
 
diff --git a/core/java/android/service/chooser/ChooserTargetService.java b/core/java/android/service/chooser/ChooserTargetService.java
index 9188806..699bd0a 100644
--- a/core/java/android/service/chooser/ChooserTargetService.java
+++ b/core/java/android/service/chooser/ChooserTargetService.java
@@ -24,6 +24,7 @@
 import android.content.IntentFilter;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.Log;
 
 import java.util.List;
 
@@ -77,9 +78,26 @@
     private final String TAG = ChooserTargetService.class.getSimpleName()
             + '[' + getClass().getSimpleName() + ']';
 
+    private static final boolean DEBUG = false;
+
+    /**
+     * The Intent action that a ChooserTargetService must respond to
+     */
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.service.chooser.ChooserTargetService";
 
+    /**
+     * The name of the <code>meta-data</code> element that must be present on an
+     * <code>activity</code> element in a manifest to link it to a ChooserTargetService
+     */
+    public static final String META_DATA_NAME = "android.service.chooser.chooser_target_service";
+
+    /**
+     * The permission that a ChooserTargetService must require in order to bind to it.
+     * If this permission is not enforced the system will skip that ChooserTargetService.
+     */
+    public static final String BIND_PERMISSION = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+
     private IChooserTargetServiceWrapper mWrapper = null;
 
     /**
@@ -105,7 +123,9 @@
 
     @Override
     public IBinder onBind(Intent intent) {
+        if (DEBUG) Log.d(TAG, "onBind " + intent);
         if (!SERVICE_INTERFACE.equals(intent.getAction())) {
+            if (DEBUG) Log.d(TAG, "bad intent action " + intent.getAction() + "; returning null");
             return null;
         }
 
@@ -121,9 +141,14 @@
                 IntentFilter matchedFilter, IChooserTargetResult result) throws RemoteException {
             List<ChooserTarget> targets = null;
             try {
+                if (DEBUG) {
+                    Log.d(TAG, "getChooserTargets calling onGetChooserTargets; "
+                            + targetComponentName + " filter: " + matchedFilter);
+                }
                 targets = onGetChooserTargets(targetComponentName, matchedFilter);
             } finally {
                 result.sendResult(targets);
+                if (DEBUG) Log.d(TAG, "Sent results");
             }
         }
     }
diff --git a/core/java/android/service/gatekeeper/IGateKeeperService.aidl b/core/java/android/service/gatekeeper/IGateKeeperService.aidl
new file mode 100644
index 0000000..2f3e296
--- /dev/null
+++ b/core/java/android/service/gatekeeper/IGateKeeperService.aidl
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.gatekeeper;
+
+/**
+ * Interface for communication with GateKeeper, the
+ * secure password storage daemon.
+ *
+ * This must be kept manually in sync with system/core/gatekeeperd
+ * until AIDL can generate both C++ and Java bindings.
+ *
+ * @hide
+ */
+interface IGateKeeperService {
+    /**
+     * Enrolls a password, returning the handle to the enrollment to be stored locally.
+     * @param uid The Android user ID associated to this enrollment
+     * @param currentPasswordHandle The previously enrolled handle, or null if none
+     * @param currentPassword The previously enrolled plaintext password, or null if none.
+     *                        If provided, must verify against the currentPasswordHandle.
+     * @param desiredPassword The new desired password, for which a handle will be returned
+     *                        upon success.
+     * @return the handle corresponding to desiredPassword, or null
+     */
+    byte[] enroll(int uid, in byte[] currentPasswordHandle, in byte[] currentPassword,
+            in byte[] desiredPassword);
+
+    /**
+     * Verifies an enrolled handle against a provided, plaintext blob.
+     * @param uid The Android user ID associated to this enrollment
+     * @param enrolledPasswordHandle The handle against which the provided password will be
+     *                               verified.
+     * @param The plaintext blob to verify against enrolledPassword.
+     * @return True if the authentication was successful
+     */
+    boolean verify(int uid, in byte[] enrolledPasswordHandle,
+            in byte[] providedPassword);
+    /**
+     * Verifies an enrolled handle against a provided, plaintext blob.
+     * @param uid The Android user ID associated to this enrollment
+     * @param challenge a challenge to authenticate agaisnt the device credential. If successful
+     *                  authentication occurs, this value will be written to the returned 
+     *                  authentication attestation.
+     * @param enrolledPasswordHandle The handle against which the provided password will be
+     *                               verified.
+     * @param The plaintext blob to verify against enrolledPassword.
+     * @return an opaque attestation of authentication on success, or null.
+     */
+    byte[] verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle, 
+            in byte[] providedPassword);
+}
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 56eb510..1ed4779 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -654,8 +654,7 @@
         }
         String summary = "";
         for (ZenRule automaticRule : config.automaticRules.values()) {
-            if (automaticRule.enabled && !automaticRule.snoozing
-                    && automaticRule.isTrueOrUnknown()) {
+            if (automaticRule.isAutomaticActive()) {
                 if (summary.isEmpty()) {
                     summary = automaticRule.name;
                 } else {
@@ -745,9 +744,13 @@
                     component);
         }
 
+        public boolean isAutomaticActive() {
+            return enabled && !snoozing && component != null && isTrueOrUnknown();
+        }
+
         public boolean isTrueOrUnknown() {
-            return condition == null || condition.state == Condition.STATE_TRUE
-                    || condition.state == Condition.STATE_UNKNOWN;
+            return condition != null && (condition.state == Condition.STATE_TRUE
+                    || condition.state == Condition.STATE_UNKNOWN);
         }
 
         public static final Parcelable.Creator<ZenRule> CREATOR
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 20d7079..71b7f76 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -20,8 +20,10 @@
 import android.app.Dialog;
 import android.app.Instrumentation;
 import android.app.VoiceInteractor;
+import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
@@ -65,7 +67,8 @@
  * when done.  It can also initiate voice interactions with applications by calling
  * {@link #startVoiceActivity}</p>.
  */
-public abstract class VoiceInteractionSession implements KeyEvent.Callback {
+public abstract class VoiceInteractionSession implements KeyEvent.Callback,
+        ComponentCallbacks2 {
     static final String TAG = "VoiceInteractionSession";
     static final boolean DEBUG = true;
 
@@ -855,6 +858,18 @@
         hide();
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+    }
+
+    @Override
+    public void onLowMemory() {
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+    }
+
     /**
      * Compute the interesting insets into your UI.  The default implementation
      * sets {@link Insets#contentInsets outInsets.contentInsets.top} to the height
diff --git a/core/java/android/service/voice/VoiceInteractionSessionService.java b/core/java/android/service/voice/VoiceInteractionSessionService.java
index 008d55f..8f988f3 100644
--- a/core/java/android/service/voice/VoiceInteractionSessionService.java
+++ b/core/java/android/service/voice/VoiceInteractionSessionService.java
@@ -19,6 +19,7 @@
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Looper;
@@ -76,6 +77,30 @@
         return mInterface.asBinder();
     }
 
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        if (mSession != null) {
+            mSession.onConfigurationChanged(newConfig);
+        }
+    }
+
+    @Override
+    public void onLowMemory() {
+        super.onLowMemory();
+        if (mSession != null) {
+            mSession.onLowMemory();
+        }
+    }
+
+    @Override
+    public void onTrimMemory(int level) {
+        super.onTrimMemory(level);
+        if (mSession != null) {
+            mSession.onTrimMemory(level);
+        }
+    }
+
     void doNewSession(IBinder token, Bundle args, int startFlags) {
         if (mSession != null) {
             mSession.doDestroy();
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 3fa8c81..6b28746 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1795,6 +1795,8 @@
      *                          11       PFLAG2_TEXT_DIRECTION_FLAGS[3]
      *                         1         PFLAG2_TEXT_DIRECTION_FLAGS[4]
      *                         1 1       PFLAG2_TEXT_DIRECTION_FLAGS[5]
+     *                         11        PFLAG2_TEXT_DIRECTION_FLAGS[6]
+     *                         111       PFLAG2_TEXT_DIRECTION_FLAGS[7]
      *                         111       PFLAG2_TEXT_DIRECTION_MASK
      *                        1          PFLAG2_TEXT_DIRECTION_RESOLVED
      *                       1           PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT
@@ -1968,6 +1970,20 @@
     public static final int TEXT_DIRECTION_LOCALE = 5;
 
     /**
+     * Text direction is using "first strong algorithm". The first strong directional character
+     * determines the paragraph direction. If there is no strong directional character, the
+     * paragraph direction is LTR.
+     */
+    public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6;
+
+    /**
+     * Text direction is using "first strong algorithm". The first strong directional character
+     * determines the paragraph direction. If there is no strong directional character, the
+     * paragraph direction is RTL.
+     */
+    public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7;
+
+    /**
      * Default text direction is inherited
      */
     private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
@@ -2002,7 +2018,9 @@
             TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
             TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
             TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
-            TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT
+            TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT,
+            TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT
     };
 
     /**
@@ -19636,11 +19654,13 @@
      * @return the defined text direction. It can be one of:
      *
      * {@link #TEXT_DIRECTION_INHERIT},
-     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG},
      * {@link #TEXT_DIRECTION_ANY_RTL},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
-     * {@link #TEXT_DIRECTION_LOCALE}
+     * {@link #TEXT_DIRECTION_LOCALE},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}
      *
      * @attr ref android.R.styleable#View_textDirection
      *
@@ -19652,7 +19672,9 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     public int getRawTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT;
@@ -19664,11 +19686,13 @@
      * @param textDirection the direction to set. Should be one of:
      *
      * {@link #TEXT_DIRECTION_INHERIT},
-     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG},
      * {@link #TEXT_DIRECTION_ANY_RTL},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL},
      *
      * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution
      * proceeds up the parent chain of the view to get the value. If there is no parent, then it will
@@ -19698,11 +19722,13 @@
      *
      * @return the resolved text direction. Returns one of:
      *
-     * {@link #TEXT_DIRECTION_FIRST_STRONG}
+     * {@link #TEXT_DIRECTION_FIRST_STRONG},
      * {@link #TEXT_DIRECTION_ANY_RTL},
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
-     * {@link #TEXT_DIRECTION_LOCALE}
+     * {@link #TEXT_DIRECTION_LOCALE},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR},
+     * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}
      *
      * @attr ref android.R.styleable#View_textDirection
      */
@@ -19712,7 +19738,9 @@
             @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"),
             @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"),
-            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE")
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"),
+            @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL")
     })
     public int getTextDirection() {
         return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
@@ -19771,6 +19799,8 @@
                         case TEXT_DIRECTION_LTR:
                         case TEXT_DIRECTION_RTL:
                         case TEXT_DIRECTION_LOCALE:
+                        case TEXT_DIRECTION_FIRST_STRONG_LTR:
+                        case TEXT_DIRECTION_FIRST_STRONG_RTL:
                             mPrivateFlags2 |=
                                     (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
                             break;
@@ -19784,6 +19814,8 @@
                 case TEXT_DIRECTION_LTR:
                 case TEXT_DIRECTION_RTL:
                 case TEXT_DIRECTION_LOCALE:
+                case TEXT_DIRECTION_FIRST_STRONG_LTR:
+                case TEXT_DIRECTION_FIRST_STRONG_RTL:
                     // Resolved direction is the same as text direction
                     mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT);
                     break;
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index f951dc2..e0b0e1f 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -40,7 +40,6 @@
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ListPopupWindow.ForwardingListener;
-import com.android.internal.transition.ActionBarTransition;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.ActionMenuItemView;
 import com.android.internal.view.menu.BaseMenuPresenter;
@@ -99,7 +98,30 @@
 
     // The list of currently running animations on menu items.
     private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>();
+    private ViewTreeObserver.OnPreDrawListener mItemAnimationPreDrawListener =
+            new ViewTreeObserver.OnPreDrawListener() {
+        @Override
+        public boolean onPreDraw() {
+            computeMenuItemAnimationInfo(false);
+            ((View) mMenuView).getViewTreeObserver().removeOnPreDrawListener(this);
+            runItemAnimations();
+            return true;
+        }
+    };
+    private View.OnAttachStateChangeListener mAttachStateChangeListener =
+            new View.OnAttachStateChangeListener() {
+        @Override
+        public void onViewAttachedToWindow(View v) {
+        }
 
+        @Override
+        public void onViewDetachedFromWindow(View v) {
+            ((View) mMenuView).getViewTreeObserver().removeOnPreDrawListener(
+                    mItemAnimationPreDrawListener);
+            mPreLayoutItems.clear();
+            mPostLayoutItems.clear();
+        }
+    };
 
 
     public ActionMenuPresenter(Context context) {
@@ -177,8 +199,15 @@
 
     @Override
     public MenuView getMenuView(ViewGroup root) {
+        MenuView oldMenuView = mMenuView;
         MenuView result = super.getMenuView(root);
-        ((ActionMenuView) result).setPresenter(this);
+        if (oldMenuView != result) {
+            ((ActionMenuView) result).setPresenter(this);
+            if (oldMenuView != null) {
+                ((View) oldMenuView).removeOnAttachStateChangeListener(mAttachStateChangeListener);
+            }
+            ((View) result).addOnAttachStateChangeListener(mAttachStateChangeListener);
+        }
         return result;
     }
 
@@ -226,11 +255,11 @@
      * 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();
+        final ViewGroup menuView = (ViewGroup) mMenuView;
+        final int count = menuView.getChildCount();
         SparseArray items = preLayout ? mPreLayoutItems : mPostLayoutItems;
         for (int i = 0; i < count; ++i) {
-            View child = menuViewParent.getChildAt(i);
+            View child = menuView.getChildAt(i);
             final int id = child.getId();
             if (id > 0 && child.getWidth() != 0 && child.getHeight() != 0) {
                 MenuItemLayoutInfo info = new MenuItemLayoutInfo(child, preLayout);
@@ -377,28 +406,16 @@
      * 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;
-                }
-            });
-        }
+        ((View) mMenuView).getViewTreeObserver().
+                addOnPreDrawListener(mItemAnimationPreDrawListener);
     }
 
     @Override
     public void updateMenuView(boolean cleared) {
         final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent();
         if (menuViewParent != null) {
-//            setupItemAnimations();
-            ActionBarTransition.beginDelayedTransition(menuViewParent);
+            setupItemAnimations();
         }
         super.updateMenuView(cleared);
 
@@ -736,8 +753,14 @@
     }
 
     public void setMenuView(ActionMenuView menuView) {
-        mMenuView = menuView;
-        menuView.initialize(mMenu);
+        if (menuView != mMenuView) {
+            if (mMenuView != null) {
+                ((View) mMenuView).removeOnAttachStateChangeListener(mAttachStateChangeListener);
+            }
+            mMenuView = menuView;
+            menuView.initialize(mMenu);
+            menuView.addOnAttachStateChangeListener(mAttachStateChangeListener);
+        }
     }
 
     public void setOverflowTintList(ColorStateList tint) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 29073be..1be05f3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -3370,7 +3370,7 @@
         // Parent's (TextView) previous position in window
         private int mLastParentX, mLastParentY;
         // Previous text character offset
-        private int mPreviousOffset = -1;
+        protected int mPreviousOffset = -1;
         // Previous text character offset
         private boolean mPositionHasChanged = true;
         // Minimum touch target size for handles
@@ -3830,8 +3830,6 @@
     }
 
     private class SelectionStartHandleView extends HandleView {
-        // The previous offset this handle was at.
-        private int mPrevOffset;
         // Indicates whether the cursor is making adjustments within a word.
         private boolean mInWord = false;
         // Offset to track difference between touch and word boundary.
@@ -3879,7 +3877,7 @@
             int end = getWordEnd(offset, true);
             int start = getWordStart(offset);
 
-            if (offset < mPrevOffset) {
+            if (offset < mPreviousOffset) {
                 // User is increasing the selection.
                 if (!mInWord || currLine < mPrevLine) {
                     // We're not in a word, or we're on a different line so we'll expand by
@@ -3888,21 +3886,19 @@
                     if (offset <= end - offsetToWord || currLine < mPrevLine) {
                         offset = start;
                     } else {
-                        offset = mPrevOffset;
+                        offset = mPreviousOffset;
                     }
                 }
-                mPrevOffset = offset;
                 mTouchWordOffset = Math.max(trueOffset - offset, 0);
                 mInWord = !isStartBoundary(offset);
                 positionCursor = true;
-            } else if (offset - mTouchWordOffset > mPrevOffset) {
+            } else if (offset - mTouchWordOffset > mPreviousOffset) {
                 // User is shrinking the selection.
                 if (currLine > mPrevLine) {
                     // We're on a different line, so we'll snap to word boundaries.
                     offset = end;
                 }
                 offset -= mTouchWordOffset;
-                mPrevOffset = offset;
                 mInWord = !isEndBoundary(offset);
                 positionCursor = true;
             }
@@ -3936,8 +3932,6 @@
     }
 
     private class SelectionEndHandleView extends HandleView {
-        // The previous offset this handle was at.
-        private int mPrevOffset;
         // Indicates whether the cursor is making adjustments within a word.
         private boolean mInWord = false;
         // Offset to track difference between touch and word boundary.
@@ -3986,7 +3980,7 @@
             int end = getWordEnd(offset, true);
             int start = getWordStart(offset);
 
-            if (offset > mPrevOffset) {
+            if (offset > mPreviousOffset) {
                 // User is increasing the selection.
                 if (!mInWord || currLine > mPrevLine) {
                     // We're not in a word, or we're on a different line so we'll expand by
@@ -3995,21 +3989,19 @@
                     if (offset >= start + midPoint || currLine > mPrevLine) {
                         offset = end;
                     } else {
-                        offset = mPrevOffset;
+                        offset = mPreviousOffset;
                     }
                 }
-                mPrevOffset = offset;
                 mTouchWordOffset = Math.max(offset - trueOffset, 0);
                 mInWord = !isEndBoundary(offset);
                 positionCursor = true;
-            } else if (offset + mTouchWordOffset < mPrevOffset) {
+            } else if (offset + mTouchWordOffset < mPreviousOffset) {
                 // User is shrinking the selection.
                 if (currLine > mPrevLine) {
                     // We're on a different line, so we'll snap to word boundaries.
                     offset = getWordStart(offset);
                 }
                 offset += mTouchWordOffset;
-                mPrevOffset = offset;
                 positionCursor = true;
                 mInWord = !isStartBoundary(offset);
             }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9bbf375..b44a886 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -9275,6 +9275,10 @@
                 return TextDirectionHeuristics.RTL;
             case TEXT_DIRECTION_LOCALE:
                 return TextDirectionHeuristics.LOCALE;
+            case TEXT_DIRECTION_FIRST_STRONG_LTR:
+                return TextDirectionHeuristics.FIRSTSTRONG_LTR;
+            case TEXT_DIRECTION_FIRST_STRONG_RTL:
+                return TextDirectionHeuristics.FIRSTSTRONG_RTL;
         }
     }
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 64bd6b6..8403e77 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -18,20 +18,87 @@
 
 import android.app.Activity;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
+import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.chooser.ChooserTarget;
+import android.service.chooser.ChooserTargetService;
+import android.service.chooser.IChooserTargetResult;
+import android.service.chooser.IChooserTargetService;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Slog;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
 
 public class ChooserActivity extends ResolverActivity {
     private static final String TAG = "ChooserActivity";
 
+    private static final boolean DEBUG = false;
+
+    private static final int QUERY_TARGET_LIMIT = 5;
+    private static final int WATCHDOG_TIMEOUT_MILLIS = 5000;
+
     private Bundle mReplacementExtras;
     private IntentSender mChosenComponentSender;
 
+    private ChooserTarget[] mCallerChooserTargets;
+
+    private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
+
+    private static final int CHOOSER_TARGET_SERVICE_RESULT = 1;
+    private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT = 2;
+
+    private Handler mTargetResultHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case CHOOSER_TARGET_SERVICE_RESULT:
+                    if (DEBUG) Log.d(TAG, "CHOOSER_TARGET_SERVICE_RESULT");
+                    if (isDestroyed()) break;
+                    final ServiceResultInfo sri = (ServiceResultInfo) msg.obj;
+                    if (!mServiceConnections.contains(sri.connection)) {
+                        Log.w(TAG, "ChooserTargetServiceConnection " + sri.connection
+                                + " returned after being removed from active connections."
+                                + " Have you considered returning results faster?");
+                        break;
+                    }
+                    final ChooserListAdapter cla = (ChooserListAdapter) getAdapter();
+                    cla.addServiceResults(sri.originalTarget, sri.resultTargets);
+                    unbindService(sri.connection);
+                    mServiceConnections.remove(sri.connection);
+                    break;
+
+                case CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT:
+                    if (DEBUG) {
+                        Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services");
+                    }
+                    unbindRemainingServices();
+                    break;
+
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    };
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         Intent intent = getIntent();
@@ -42,7 +109,7 @@
             super.onCreate(null);
             return;
         }
-        Intent target = (Intent)targetParcelable;
+        Intent target = (Intent) targetParcelable;
         if (target != null) {
             modifyTargetIntent(target);
         }
@@ -68,6 +135,22 @@
                 initialIntents[i] = in;
             }
         }
+
+        pa = intent.getParcelableArrayExtra(Intent.EXTRA_CHOOSER_TARGETS);
+        if (pa != null) {
+            final ChooserTarget[] targets = new ChooserTarget[pa.length];
+            for (int i = 0; i < pa.length; i++) {
+                if (!(pa[i] instanceof ChooserTarget)) {
+                    Log.w("ChooserActivity", "Chooser target #" + i + " is not a ChooserTarget: " +
+                            pa[i]);
+                    finish();
+                    super.onCreate(null);
+                    return;
+                }
+                targets[i] = (ChooserTarget) pa[i];
+            }
+            mCallerChooserTargets = targets;
+        }
         mChosenComponentSender = intent.getParcelableExtra(
                 Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER);
         setSafeForwardingMode(true);
@@ -94,9 +177,9 @@
     }
 
     @Override
-    public void onActivityStarted(Intent intent) {
+    void onActivityStarted(TargetInfo cti) {
         if (mChosenComponentSender != null) {
-            final ComponentName target = intent.getComponent();
+            final ComponentName target = cti.getResolvedComponentName();
             if (target != null) {
                 final Intent fillIn = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, target);
                 try {
@@ -109,6 +192,16 @@
         }
     }
 
+    @Override
+    int getLayoutResource() {
+        return com.android.internal.R.layout.chooser_grid;
+    }
+
+    @Override
+    boolean shouldGetActivityMetadata() {
+        return true;
+    }
+
     private void modifyTargetIntent(Intent in) {
         final String action = in.getAction();
         if (Intent.ACTION_SEND.equals(action) ||
@@ -117,4 +210,297 @@
                     Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
         }
     }
+
+    void queryTargetServices(ChooserListAdapter adapter) {
+        final PackageManager pm = getPackageManager();
+        int targetsToQuery = 0;
+        for (int i = 0, N = adapter.getDisplayResolveInfoCount(); i < N; i++) {
+            final DisplayResolveInfo dri = adapter.getDisplayResolveInfo(i);
+            final ActivityInfo ai = dri.getResolveInfo().activityInfo;
+            final Bundle md = ai.metaData;
+            final String serviceName = md != null ? convertServiceName(ai.packageName,
+                    md.getString(ChooserTargetService.META_DATA_NAME)) : null;
+            if (serviceName != null) {
+                final ComponentName serviceComponent = new ComponentName(
+                        ai.packageName, serviceName);
+                final Intent serviceIntent = new Intent(ChooserTargetService.SERVICE_INTERFACE)
+                        .setComponent(serviceComponent);
+
+                if (DEBUG) {
+                    Log.d(TAG, "queryTargets found target with service " + serviceComponent);
+                }
+
+                try {
+                    final String perm = pm.getServiceInfo(serviceComponent, 0).permission;
+                    if (!ChooserTargetService.BIND_PERMISSION.equals(perm)) {
+                        Log.w(TAG, "ChooserTargetService " + serviceComponent + " does not require"
+                                + " permission " + ChooserTargetService.BIND_PERMISSION
+                                + " - this service will not be queried for ChooserTargets."
+                                + " add android:permission=\""
+                                + ChooserTargetService.BIND_PERMISSION + "\""
+                                + " to the <service> tag for " + serviceComponent
+                                + " in the manifest.");
+                        continue;
+                    }
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Could not look up service " + serviceComponent, e);
+                    continue;
+                }
+
+                final ChooserTargetServiceConnection conn = new ChooserTargetServiceConnection(dri);
+                if (bindServiceAsUser(serviceIntent, conn, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND,
+                        UserHandle.CURRENT)) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Binding service connection for target " + dri
+                                + " intent " + serviceIntent);
+                    }
+                    mServiceConnections.add(conn);
+                    targetsToQuery++;
+                }
+            }
+            if (targetsToQuery >= QUERY_TARGET_LIMIT) {
+                if (DEBUG) Log.d(TAG, "queryTargets hit query target limit " + QUERY_TARGET_LIMIT);
+                break;
+            }
+        }
+
+        if (!mServiceConnections.isEmpty()) {
+            if (DEBUG) Log.d(TAG, "queryTargets setting watchdog timer for "
+                    + WATCHDOG_TIMEOUT_MILLIS + "ms");
+            mTargetResultHandler.sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT,
+                    WATCHDOG_TIMEOUT_MILLIS);
+        }
+    }
+
+    private String convertServiceName(String packageName, String serviceName) {
+        if (TextUtils.isEmpty(serviceName)) {
+            return null;
+        }
+
+        final String fullName;
+        if (serviceName.startsWith(".")) {
+            // Relative to the app package. Prepend the app package name.
+            fullName = packageName + serviceName;
+        } else if (serviceName.indexOf('.') >= 0) {
+            // Fully qualified package name.
+            fullName = serviceName;
+        } else {
+            fullName = null;
+        }
+        return fullName;
+    }
+
+    void unbindRemainingServices() {
+        if (DEBUG) {
+            Log.d(TAG, "unbindRemainingServices, " + mServiceConnections.size() + " left");
+        }
+        for (int i = 0, N = mServiceConnections.size(); i < N; i++) {
+            final ChooserTargetServiceConnection conn = mServiceConnections.get(i);
+            if (DEBUG) Log.d(TAG, "unbinding " + conn);
+            unbindService(conn);
+        }
+        mServiceConnections.clear();
+        mTargetResultHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
+    }
+
+    @Override
+    ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
+            List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
+        final ChooserListAdapter adapter = new ChooserListAdapter(context, initialIntents, rList,
+                launchedFromUid, filterLastUsed);
+        if (DEBUG) Log.d(TAG, "Adapter created; querying services");
+        queryTargetServices(adapter);
+        return adapter;
+    }
+
+    class ChooserTargetInfo implements TargetInfo {
+        private final TargetInfo mSourceInfo;
+        private final ChooserTarget mChooserTarget;
+        private final Drawable mDisplayIcon;
+
+        public ChooserTargetInfo(TargetInfo sourceInfo, ChooserTarget chooserTarget) {
+            mSourceInfo = sourceInfo;
+            mChooserTarget = chooserTarget;
+            mDisplayIcon = new BitmapDrawable(getResources(), chooserTarget.getIcon());
+        }
+
+        @Override
+        public Intent getResolvedIntent() {
+            final Intent targetIntent = mChooserTarget.getIntent();
+            return targetIntent != null ? targetIntent : mSourceInfo.getResolvedIntent();
+        }
+
+        @Override
+        public ComponentName getResolvedComponentName() {
+            return mSourceInfo.getResolvedComponentName();
+        }
+
+        @Override
+        public boolean start(Activity activity, Bundle options) {
+            return mChooserTarget.sendIntent(activity, mSourceInfo.getResolvedIntent());
+        }
+
+        @Override
+        public boolean startAsCaller(Activity activity, Bundle options, int userId) {
+            return mChooserTarget.sendIntentAsCaller(activity, mSourceInfo.getResolvedIntent(),
+                    userId);
+        }
+
+        @Override
+        public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+            return mChooserTarget.sendIntentAsUser(activity, mSourceInfo.getResolvedIntent(), user);
+        }
+
+        @Override
+        public ResolveInfo getResolveInfo() {
+            return mSourceInfo.getResolveInfo();
+        }
+
+        @Override
+        public CharSequence getDisplayLabel() {
+            return mChooserTarget.getTitle();
+        }
+
+        @Override
+        public CharSequence getExtendedInfo() {
+            return mSourceInfo.getExtendedInfo();
+        }
+
+        @Override
+        public Drawable getDisplayIcon() {
+            return mDisplayIcon;
+        }
+    }
+
+    public class ChooserListAdapter extends ResolveListAdapter {
+        private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
+
+        public ChooserListAdapter(Context context, Intent[] initialIntents, List<ResolveInfo> rList,
+                int launchedFromUid, boolean filterLastUsed) {
+            super(context, initialIntents, rList, launchedFromUid, filterLastUsed);
+        }
+
+        @Override
+        public boolean showsExtendedInfo(TargetInfo info) {
+            // Reserve space to show extended info if any one of the items in the adapter has
+            // extended info. This keeps grid item sizes uniform.
+            return hasExtendedInfo();
+        }
+
+        @Override
+        public View createView(ViewGroup parent) {
+            return mInflater.inflate(
+                    com.android.internal.R.layout.resolve_grid_item, parent, false);
+        }
+
+        @Override
+        public void onListRebuilt() {
+            if (mServiceTargets != null) {
+                pruneServiceTargets();
+            }
+        }
+
+        @Override
+        public int getCount() {
+            int count = super.getCount();
+            if (mServiceTargets != null) {
+                count += mServiceTargets.size();
+            }
+            return count;
+        }
+
+        @Override
+        public TargetInfo getItem(int position) {
+            int offset = 0;
+            if (mServiceTargets != null) {
+                final int serviceTargetCount = mServiceTargets.size();
+                if (position < serviceTargetCount) {
+                    return mServiceTargets.get(position);
+                }
+                offset += serviceTargetCount;
+            }
+            return super.getItem(position - offset);
+        }
+
+        public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets) {
+            if (DEBUG) Log.d(TAG, "addServiceResults " + origTarget + ", " + targets.size()
+                    + " targets");
+            for (int i = 0, N = targets.size(); i < N; i++) {
+                mServiceTargets.add(new ChooserTargetInfo(origTarget, targets.get(i)));
+            }
+
+            // TODO: Maintain sort by ranking scores.
+
+            notifyDataSetChanged();
+        }
+
+        private void pruneServiceTargets() {
+            if (DEBUG) Log.d(TAG, "pruneServiceTargets");
+            for (int i = mServiceTargets.size() - 1; i >= 0; i--) {
+                final ChooserTargetInfo cti = mServiceTargets.get(i);
+                if (!hasResolvedTarget(cti.getResolveInfo())) {
+                    if (DEBUG) Log.d(TAG, " => " + i + " " + cti);
+                    mServiceTargets.remove(i);
+                }
+            }
+        }
+    }
+
+    class ChooserTargetServiceConnection implements ServiceConnection {
+        private final DisplayResolveInfo mOriginalTarget;
+
+        private final IChooserTargetResult mChooserTargetResult = new IChooserTargetResult.Stub() {
+            @Override
+            public void sendResult(List<ChooserTarget> targets) throws RemoteException {
+                final Message msg = Message.obtain();
+                msg.what = CHOOSER_TARGET_SERVICE_RESULT;
+                msg.obj = new ServiceResultInfo(mOriginalTarget, targets,
+                        ChooserTargetServiceConnection.this);
+                mTargetResultHandler.sendMessage(msg);
+            }
+        };
+
+        public ChooserTargetServiceConnection(DisplayResolveInfo dri) {
+            mOriginalTarget = dri;
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            if (DEBUG) Log.d(TAG, "onServiceConnected: " + name);
+            final IChooserTargetService icts = IChooserTargetService.Stub.asInterface(service);
+            try {
+                icts.getChooserTargets(mOriginalTarget.getResolvedComponentName(),
+                        mOriginalTarget.getResolveInfo().filter, mChooserTargetResult);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Querying ChooserTargetService " + name + " failed.", e);
+                unbindService(this);
+                mServiceConnections.remove(this);
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
+            unbindService(this);
+            mServiceConnections.remove(this);
+        }
+
+        @Override
+        public String toString() {
+            return mOriginalTarget.getResolveInfo().activityInfo.toString();
+        }
+    }
+
+    static class ServiceResultInfo {
+        public final DisplayResolveInfo originalTarget;
+        public final List<ChooserTarget> resultTargets;
+        public final ChooserTargetServiceConnection connection;
+
+        public ServiceResultInfo(DisplayResolveInfo ot, List<ChooserTarget> rt,
+                ChooserTargetServiceConnection c) {
+            originalTarget = ot;
+            resultTargets = rt;
+            connection = c;
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 6b35f3f..3cd69a1 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -25,6 +25,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.widget.AbsListView;
+import android.widget.GridView;
 import com.android.internal.R;
 import com.android.internal.content.PackageMonitor;
 
@@ -91,15 +92,14 @@
     private PackageManager mPm;
     private boolean mSafeForwardingMode;
     private boolean mAlwaysUseOption;
-    private boolean mShowExtended;
+    private AbsListView mAdapterView;
     private ListView mListView;
+    private GridView mGridView;
     private Button mAlwaysButton;
     private Button mOnceButton;
     private View mProfileView;
     private int mIconDpi;
-    private int mIconSize;
-    private int mMaxColumns;
-    private int mLastSelected = ListView.INVALID_POSITION;
+    private int mLastSelected = AbsListView.INVALID_POSITION;
     private boolean mResolvingHome = false;
     private int mProfileSwitchMessageId = -1;
     private Intent mIntent;
@@ -192,7 +192,7 @@
     }
 
     /**
-     * Compatibility version for other bundled services that use this ocerload without
+     * Compatibility version for other bundled services that use this overload without
      * a default title resource
      */
     protected void onCreate(Bundle savedInstanceState, Intent intent,
@@ -223,18 +223,14 @@
         final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
         mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());
 
-        mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
-
         mPackageMonitor.register(this, getMainLooper(), false);
         mRegistered = true;
 
         final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
         mIconDpi = am.getLauncherLargeIconDensity();
-        mIconSize = am.getLauncherLargeIconSize();
 
         mIntent = new Intent(intent);
-        mAdapter = new ResolveListAdapter(this, initialIntents, rList,
-                mLaunchedFromUid, alwaysUseOption);
+        mAdapter = createAdapter(this, initialIntents, rList, mLaunchedFromUid, alwaysUseOption);
 
         final int layoutId;
         final boolean useHeader;
@@ -244,7 +240,7 @@
             useHeader = true;
         } else {
             useHeader = false;
-            layoutId = R.layout.resolver_list;
+            layoutId = getLayoutResource();
         }
         mAlwaysUseOption = alwaysUseOption;
 
@@ -257,21 +253,30 @@
         int count = mAdapter.mList.size();
         if (count > 1 || (count == 1 && mAdapter.getOtherProfile() != null)) {
             setContentView(layoutId);
-            mListView = (ListView) findViewById(R.id.resolver_list);
-            mListView.setAdapter(mAdapter);
-            mListView.setOnItemClickListener(this);
-            mListView.setOnItemLongClickListener(new ItemLongClickListener());
+            mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
+            mAdapterView.setAdapter(mAdapter);
+            mAdapterView.setOnItemClickListener(this);
+            mAdapterView.setOnItemLongClickListener(new ItemLongClickListener());
 
-            if (alwaysUseOption) {
-                mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+            // Initialize the different types of collection views we may have. Depending
+            // on which ones are initialized later we'll configure different properties.
+            if (mAdapterView instanceof ListView) {
+                mListView = (ListView) mAdapterView;
+            }
+            if (mAdapterView instanceof GridView) {
+                mGridView = (GridView) mAdapterView;
             }
 
-            if (useHeader) {
+            if (alwaysUseOption) {
+                mAdapterView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
+            }
+
+            if (useHeader && mListView != null) {
                 mListView.addHeaderView(LayoutInflater.from(this).inflate(
                         R.layout.resolver_different_item_header, mListView, false));
             }
         } else if (count == 1) {
-            safelyStartActivity(mAdapter.intentForPosition(0, false));
+            safelyStartActivity(mAdapter.targetInfoForPosition(0, false));
             mPackageMonitor.unregister();
             mRegistered = false;
             finish();
@@ -282,8 +287,8 @@
             final TextView empty = (TextView) findViewById(R.id.empty);
             empty.setVisibility(View.VISIBLE);
 
-            mListView = (ListView) findViewById(R.id.resolver_list);
-            mListView.setVisibility(View.GONE);
+            mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
+            mAdapterView.setVisibility(View.GONE);
         }
         // Prevent the Resolver window from becoming the top fullscreen window and thus from taking
         // control of the system bars.
@@ -308,12 +313,30 @@
                 titleView.setText(title);
             }
             setTitle(title);
+
+            // Try to initialize the title icon if we have a view for it and a title to match
+            final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
+            if (titleIcon != null) {
+                final String referrerPackage = getReferrerPackageName();
+                ApplicationInfo ai = null;
+                try {
+                    if (!TextUtils.isEmpty(referrerPackage)) {
+                        ai = mPm.getApplicationInfo(referrerPackage, 0);
+                    }
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Could not find referrer package " + referrerPackage);
+                }
+
+                if (ai != null) {
+                    titleIcon.setImageDrawable(ai.loadIcon(mPm));
+                }
+            }
         }
 
         final ImageView iconView = (ImageView) findViewById(R.id.icon);
         final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem();
         if (iconView != null && iconInfo != null) {
-            new LoadIconIntoViewTask(iconView).execute(iconInfo);
+            new LoadIconIntoViewTask(iconInfo, iconView).execute();
         }
 
         if (alwaysUseOption || mAdapter.hasFilteredItem()) {
@@ -345,8 +368,7 @@
                     // Do not show the profile switch message anymore.
                     mProfileSwitchMessageId = -1;
 
-                    final Intent intent = intentForDisplayResolveInfo(dri);
-                    onIntentSelected(dri.ri, intent, false);
+                    onTargetSelected(dri, false);
                     finish();
                 }
             });
@@ -354,17 +376,29 @@
         }
     }
 
+    private String getReferrerPackageName() {
+        final Uri referrer = getReferrer();
+        if (referrer != null && "android-app".equals(referrer.getScheme())) {
+            return referrer.getHost();
+        }
+        return null;
+    }
+
+    int getLayoutResource() {
+        return R.layout.resolver_list;
+    }
+
     void bindProfileView() {
         final DisplayResolveInfo dri = mAdapter.getOtherProfile();
         if (dri != null) {
             mProfileView.setVisibility(View.VISIBLE);
             final ImageView icon = (ImageView) mProfileView.findViewById(R.id.icon);
             final TextView text = (TextView) mProfileView.findViewById(R.id.text1);
-            if (dri.displayIcon == null) {
-                new LoadIconTask().execute(dri);
+            if (!dri.hasDisplayIcon()) {
+                new LoadIconIntoViewTask(dri, icon).execute();
             }
-            icon.setImageDrawable(dri.displayIcon);
-            text.setText(dri.displayLabel);
+            icon.setImageDrawable(dri.getDisplayIcon());
+            text.setText(dri.getDisplayLabel());
         } else {
             mProfileView.setVisibility(View.GONE);
         }
@@ -408,8 +442,9 @@
         if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
             return getString(defaultTitleRes);
         } else {
-            return named ? getString(title.namedTitleRes, mAdapter.getFilteredItem().displayLabel) :
-                    getString(title.titleRes);
+            return named
+                    ? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
+                    : getString(title.titleRes);
         }
     }
 
@@ -490,31 +525,33 @@
     protected void onRestoreInstanceState(Bundle savedInstanceState) {
         super.onRestoreInstanceState(savedInstanceState);
         if (mAlwaysUseOption) {
-            final int checkedPos = mListView.getCheckedItemPosition();
+            final int checkedPos = mAdapterView.getCheckedItemPosition();
             final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
             mLastSelected = checkedPos;
             setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
             mOnceButton.setEnabled(hasValidSelection);
             if (hasValidSelection) {
-                mListView.setSelection(checkedPos);
+                mAdapterView.setSelection(checkedPos);
             }
         }
     }
 
     @Override
     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        position -= mListView.getHeaderViewsCount();
+        if (mListView != null) {
+            position -= mListView.getHeaderViewsCount();
+        }
         if (position < 0) {
             // Header views don't count.
             return;
         }
-        final int checkedPos = mListView.getCheckedItemPosition();
+        final int checkedPos = mAdapterView.getCheckedItemPosition();
         final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
         if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
             setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
             mOnceButton.setEnabled(hasValidSelection);
             if (hasValidSelection) {
-                mListView.smoothScrollToPosition(checkedPos);
+                mAdapterView.smoothScrollToPosition(checkedPos);
             }
             mLastSelected = checkedPos;
         } else {
@@ -570,7 +607,7 @@
     public void onButtonClick(View v) {
         final int id = v.getId();
         startSelected(mAlwaysUseOption ?
-                mListView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
+                        mAdapterView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
                 id == R.id.button_always,
                 mAlwaysUseOption);
     }
@@ -588,8 +625,8 @@
             return;
         }
 
-        Intent intent = mAdapter.intentForPosition(which, filtered);
-        onIntentSelected(ri, intent, always);
+        TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
+        onTargetSelected(target, always);
         finish();
     }
 
@@ -600,8 +637,12 @@
         return defIntent;
     }
 
-    protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
-        if ((mAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mOrigResolveList != null) {
+    protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
+        final ResolveInfo ri = target.getResolveInfo();
+        final Intent intent = target != null ? target.getResolvedIntent() : null;
+
+        if (intent != null && (mAlwaysUseOption || mAdapter.hasFilteredItem())
+                && mAdapter.mOrigResolveList != null) {
             // Build a reasonable intent filter, based on what matched.
             IntentFilter filter = new IntentFilter();
             String action = intent.getAction();
@@ -617,7 +658,7 @@
             }
             filter.addCategory(Intent.CATEGORY_DEFAULT);
 
-            int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
+            int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
             Uri data = intent.getData();
             if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
                 String mimeType = intent.resolveType(this);
@@ -726,25 +767,27 @@
             }
         }
 
-        if (intent != null) {
-            safelyStartActivity(intent);
+        if (target != null) {
+            safelyStartActivity(target);
         }
     }
 
-    public void safelyStartActivity(Intent intent) {
+    void safelyStartActivity(TargetInfo cti) {
         // If needed, show that intent is forwarded
         // from managed profile to owner or other way around.
         if (mProfileSwitchMessageId != -1) {
             Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
         }
         if (!mSafeForwardingMode) {
-            startActivity(intent);
-            onActivityStarted(intent);
+            if (cti.start(this, null)) {
+                onActivityStarted(cti);
+            }
             return;
         }
         try {
-            startActivityAsCaller(intent, null, UserHandle.USER_NULL);
-            onActivityStarted(intent);
+            if (cti.startAsCaller(this, null, UserHandle.USER_NULL)) {
+                onActivityStarted(cti);
+            }
         } catch (RuntimeException e) {
             String launchedFromPackage;
             try {
@@ -759,51 +802,197 @@
         }
     }
 
-    public void onActivityStarted(Intent intent) {
+    void onActivityStarted(TargetInfo cti) {
         // Do nothing
     }
 
+    boolean shouldGetActivityMetadata() {
+        return false;
+    }
+
     void showAppDetails(ResolveInfo ri) {
         Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
-                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
+                .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
         startActivity(in);
     }
 
-    Intent intentForDisplayResolveInfo(DisplayResolveInfo dri) {
-        Intent intent = new Intent(dri.origIntent != null ? dri.origIntent :
-                getReplacementIntent(dri.ri.activityInfo, mIntent));
-        intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
-                |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
-        ActivityInfo ai = dri.ri.activityInfo;
-        intent.setComponent(new ComponentName(
-                ai.applicationInfo.packageName, ai.name));
-        return intent;
+    ResolveListAdapter createAdapter(Context context, Intent[] initialIntents,
+            List<ResolveInfo> rList, int launchedFromUid, boolean filterLastUsed) {
+        return new ResolveListAdapter(context, initialIntents, rList, launchedFromUid,
+                filterLastUsed);
     }
 
-    private final class DisplayResolveInfo {
-        ResolveInfo ri;
-        CharSequence displayLabel;
-        Drawable displayIcon;
-        CharSequence extendedInfo;
-        Intent origIntent;
+    ResolveListAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    final class DisplayResolveInfo implements TargetInfo {
+        private final ResolveInfo mResolveInfo;
+        private final CharSequence mDisplayLabel;
+        private Drawable mDisplayIcon;
+        private final CharSequence mExtendedInfo;
+        private final Intent mResolvedIntent;
 
         DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,
                 CharSequence pInfo, Intent pOrigIntent) {
-            ri = pri;
-            displayLabel = pLabel;
-            extendedInfo = pInfo;
-            origIntent = pOrigIntent;
+            mResolveInfo = pri;
+            mDisplayLabel = pLabel;
+            mExtendedInfo = pInfo;
+
+            final Intent intent = new Intent(pOrigIntent != null ? pOrigIntent :
+                    getReplacementIntent(pri.activityInfo, mIntent));
+            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                    | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
+            final ActivityInfo ai = mResolveInfo.activityInfo;
+            intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
+
+            mResolvedIntent = intent;
+        }
+
+        public ResolveInfo getResolveInfo() {
+            return mResolveInfo;
+        }
+
+        public CharSequence getDisplayLabel() {
+            return mDisplayLabel;
+        }
+
+        public Drawable getDisplayIcon() {
+            return mDisplayIcon;
+        }
+
+        public void setDisplayIcon(Drawable icon) {
+            mDisplayIcon = icon;
+        }
+
+        public boolean hasDisplayIcon() {
+            return mDisplayIcon != null;
+        }
+
+        public CharSequence getExtendedInfo() {
+            return mExtendedInfo;
+        }
+
+        public Intent getResolvedIntent() {
+            return mResolvedIntent;
+        }
+
+        @Override
+        public ComponentName getResolvedComponentName() {
+            return new ComponentName(mResolveInfo.activityInfo.packageName,
+                    mResolveInfo.activityInfo.name);
+        }
+
+        @Override
+        public boolean start(Activity activity, Bundle options) {
+            activity.startActivity(mResolvedIntent, options);
+            return true;
+        }
+
+        @Override
+        public boolean startAsCaller(Activity activity, Bundle options, int userId) {
+            activity.startActivityAsCaller(mResolvedIntent, options, userId);
+            return true;
+        }
+
+        @Override
+        public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
+            activity.startActivityAsUser(mResolvedIntent, options, user);
+            return false;
         }
     }
 
-    private final class ResolveListAdapter extends BaseAdapter {
+    /**
+     * A single target as represented in the chooser.
+     */
+    public interface TargetInfo {
+        /**
+         * Get the resolved intent that represents this target. Note that this may not be the
+         * intent that will be launched by calling one of the <code>start</code> methods provided;
+         * this is the intent that will be credited with the launch.
+         *
+         * @return the resolved intent for this target
+         */
+        public Intent getResolvedIntent();
+
+        /**
+         * Get the resolved component name that represents this target. Note that this may not
+         * be the component that will be directly launched by calling one of the <code>start</code>
+         * methods provided; this is the component that will be credited with the launch.
+         *
+         * @return the resolved ComponentName for this target
+         */
+        public ComponentName getResolvedComponentName();
+
+        /**
+         * Start the activity referenced by this target.
+         *
+         * @param activity calling Activity performing the launch
+         * @param options ActivityOptions bundle
+         * @return true if the start completed successfully
+         */
+        public boolean start(Activity activity, Bundle options);
+
+        /**
+         * Start the activity referenced by this target as if the ResolverActivity's caller
+         * was performing the start operation.
+         *
+         * @param activity calling Activity (actually) performing the launch
+         * @param options ActivityOptions bundle
+         * @param userId userId to start as or {@link UserHandle#USER_NULL} for activity's caller
+         * @return true if the start completed successfully
+         */
+        public boolean startAsCaller(Activity activity, Bundle options, int userId);
+
+        /**
+         * Start the activity referenced by this target as a given user.
+         *
+         * @param activity calling activity performing the launch
+         * @param options ActivityOptions bundle
+         * @param user handle for the user to start the activity as
+         * @return true if the start completed successfully
+         */
+        public boolean startAsUser(Activity activity, Bundle options, UserHandle user);
+
+        /**
+         * Return the ResolveInfo about how and why this target matched the original query
+         * for available targets.
+         *
+         * @return ResolveInfo representing this target's match
+         */
+        public ResolveInfo getResolveInfo();
+
+        /**
+         * Return the human-readable text label for this target.
+         *
+         * @return user-visible target label
+         */
+        public CharSequence getDisplayLabel();
+
+        /**
+         * Return any extended info for this target. This may be used to disambiguate
+         * otherwise identical targets.
+         *
+         * @return human-readable disambig string or null if none present
+         */
+        public CharSequence getExtendedInfo();
+
+        /**
+         * @return The drawable that should be used to represent this target
+         */
+        public Drawable getDisplayIcon();
+    }
+
+    class ResolveListAdapter extends BaseAdapter {
         private final Intent[] mInitialIntents;
         private final List<ResolveInfo> mBaseResolveList;
         private ResolveInfo mLastChosen;
         private DisplayResolveInfo mOtherProfile;
         private final int mLaunchedFromUid;
-        private final LayoutInflater mInflater;
+        private boolean mHasExtendedInfo;
+
+        protected final LayoutInflater mInflater;
 
         List<DisplayResolveInfo> mList;
         List<ResolveInfo> mOrigResolveList;
@@ -817,7 +1006,7 @@
             mBaseResolveList = rList;
             mLaunchedFromUid = launchedFromUid;
             mInflater = LayoutInflater.from(context);
-            mList = new ArrayList<DisplayResolveInfo>();
+            mList = new ArrayList<>();
             mFilterLastUsed = filterLastUsed;
             rebuildList();
         }
@@ -871,9 +1060,11 @@
             if (mBaseResolveList != null) {
                 currentResolveList = mOrigResolveList = mBaseResolveList;
             } else {
-                currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
-                        mIntent, PackageManager.MATCH_DEFAULT_ONLY
-                        | (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0));
+                currentResolveList = mOrigResolveList = mPm.queryIntentActivities(mIntent,
+                        PackageManager.MATCH_DEFAULT_ONLY
+                        | (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0)
+                        | (shouldGetActivityMetadata() ? PackageManager.GET_META_DATA : 0)
+                );
                 // Filter out any activities that the launched uid does not
                 // have permission for.  We don't do this when we have an explicit
                 // list of resolved activities, because that only happens when
@@ -961,7 +1152,7 @@
                 r0 = currentResolveList.get(0);
                 int start = 0;
                 CharSequence r0Label =  r0.loadLabel(mPm);
-                mShowExtended = false;
+                mHasExtendedInfo = false;
                 for (int i = 1; i < N; i++) {
                     if (r0Label == null) {
                         r0Label = r0.activityInfo.packageName;
@@ -989,6 +1180,12 @@
                 mLastChosenPosition = -1;
                 mFilterLastUsed = false;
             }
+
+            onListRebuilt();
+        }
+
+        public void onListRebuilt() {
+            // This space for rent
         }
 
         private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
@@ -1000,7 +1197,7 @@
                 addResolveInfo(new DisplayResolveInfo(ro, roLabel, null, null));
                 updateLastChosenPosition(ro);
             } else {
-                mShowExtended = true;
+                mHasExtendedInfo = true;
                 boolean usePkg = false;
                 CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
                 if (startApp == null) {
@@ -1049,7 +1246,7 @@
         }
 
         private void addResolveInfo(DisplayResolveInfo dri) {
-            if (dri.ri.targetUserId != UserHandle.USER_CURRENT && mOtherProfile == null) {
+            if (dri.mResolveInfo.targetUserId != UserHandle.USER_CURRENT && mOtherProfile == null) {
                 // So far we only support a single other profile at a time.
                 // The first one we see gets special treatment.
                 mOtherProfile = dri;
@@ -1059,12 +1256,11 @@
         }
 
         public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
-            return (filtered ? getItem(position) : mList.get(position)).ri;
+            return (filtered ? getItem(position) : mList.get(position)).getResolveInfo();
         }
 
-        public Intent intentForPosition(int position, boolean filtered) {
-            DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position);
-            return intentForDisplayResolveInfo(dri);
+        public TargetInfo targetInfoForPosition(int position, boolean filtered) {
+            return filtered ? getItem(position) : mList.get(position);
         }
 
         public int getCount() {
@@ -1075,7 +1271,7 @@
             return result;
         }
 
-        public DisplayResolveInfo getItem(int position) {
+        public TargetInfo getItem(int position) {
             if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
                 position++;
             }
@@ -1086,11 +1282,31 @@
             return position;
         }
 
-        public View getView(int position, View convertView, ViewGroup parent) {
+        public boolean hasExtendedInfo() {
+            return mHasExtendedInfo;
+        }
+
+        public boolean hasResolvedTarget(ResolveInfo info) {
+            for (int i = 0, N = mList.size(); i < N; i++) {
+                if (info.equals(mList.get(i).getResolveInfo())) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        protected int getDisplayResolveInfoCount() {
+            return mList.size();
+        }
+
+        protected DisplayResolveInfo getDisplayResolveInfo(int index) {
+            return mList.get(index);
+        }
+
+        public final View getView(int position, View convertView, ViewGroup parent) {
             View view = convertView;
             if (view == null) {
-                view = mInflater.inflate(
-                        com.android.internal.R.layout.resolve_list_item, parent, false);
+                view = createView(parent);
 
                 final ViewHolder holder = new ViewHolder(view);
                 view.setTag(holder);
@@ -1099,19 +1315,29 @@
             return view;
         }
 
-        private final void bindView(View view, DisplayResolveInfo info) {
+        public View createView(ViewGroup parent) {
+            return mInflater.inflate(
+                    com.android.internal.R.layout.resolve_list_item, parent, false);
+        }
+
+        public boolean showsExtendedInfo(TargetInfo info) {
+            return !TextUtils.isEmpty(info.getExtendedInfo());
+        }
+
+        private final void bindView(View view, TargetInfo info) {
             final ViewHolder holder = (ViewHolder) view.getTag();
-            holder.text.setText(info.displayLabel);
-            if (mShowExtended) {
+            holder.text.setText(info.getDisplayLabel());
+            if (showsExtendedInfo(info)) {
                 holder.text2.setVisibility(View.VISIBLE);
-                holder.text2.setText(info.extendedInfo);
+                holder.text2.setText(info.getExtendedInfo());
             } else {
                 holder.text2.setVisibility(View.GONE);
             }
-            if (info.displayIcon == null) {
-                new LoadIconTask().execute(info);
+            if (info instanceof DisplayResolveInfo
+                    && !((DisplayResolveInfo) info).hasDisplayIcon()) {
+                new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
             }
-            holder.icon.setImageDrawable(info.displayIcon);
+            holder.icon.setImageDrawable(info.getDisplayIcon());
         }
     }
 
@@ -1131,7 +1357,9 @@
 
         @Override
         public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
-            position -= mListView.getHeaderViewsCount();
+            if (mListView != null) {
+                position -= mListView.getHeaderViewsCount();
+            }
             if (position < 0) {
                 // Header views don't count.
                 return false;
@@ -1143,44 +1371,53 @@
 
     }
 
-    class LoadIconTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
-        @Override
-        protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
-            final DisplayResolveInfo info = params[0];
-            if (info.displayIcon == null) {
-                info.displayIcon = loadIconForResolveInfo(info.ri);
-            }
-            return info;
+    abstract class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
+        protected final DisplayResolveInfo mDisplayResolveInfo;
+        private final ResolveInfo mResolveInfo;
+
+        public LoadIconTask(DisplayResolveInfo dri) {
+            mDisplayResolveInfo = dri;
+            mResolveInfo = dri.getResolveInfo();
         }
 
         @Override
-        protected void onPostExecute(DisplayResolveInfo info) {
-            if (mProfileView != null && mAdapter.getOtherProfile() == info) {
+        protected Drawable doInBackground(Void... params) {
+            return loadIconForResolveInfo(mResolveInfo);
+        }
+
+        @Override
+        protected void onPostExecute(Drawable d) {
+            mDisplayResolveInfo.setDisplayIcon(d);
+        }
+    }
+
+    class LoadAdapterIconTask extends LoadIconTask {
+        public LoadAdapterIconTask(DisplayResolveInfo dri) {
+            super(dri);
+        }
+
+        @Override
+        protected void onPostExecute(Drawable d) {
+            super.onPostExecute(d);
+            if (mProfileView != null && mAdapter.getOtherProfile() == mDisplayResolveInfo) {
                 bindProfileView();
             }
             mAdapter.notifyDataSetChanged();
         }
     }
 
-    class LoadIconIntoViewTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
-        final ImageView mTargetView;
+    class LoadIconIntoViewTask extends LoadIconTask {
+        private final ImageView mTargetView;
 
-        public LoadIconIntoViewTask(ImageView target) {
+        public LoadIconIntoViewTask(DisplayResolveInfo dri, ImageView target) {
+            super(dri);
             mTargetView = target;
         }
 
         @Override
-        protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
-            final DisplayResolveInfo info = params[0];
-            if (info.displayIcon == null) {
-                info.displayIcon = loadIconForResolveInfo(info.ri);
-            }
-            return info;
-        }
-
-        @Override
-        protected void onPostExecute(DisplayResolveInfo info) {
-            mTargetView.setImageDrawable(info.displayIcon);
+        protected void onPostExecute(Drawable d) {
+            super.onPostExecute(d);
+            mTargetView.setImageDrawable(d);
         }
     }
 
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 6be6389..24b5d0d 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -26,9 +26,10 @@
  */
 public class MetricsLogger implements MetricsConstants {
     // These constants are temporary, they should migrate to MetricsConstants.
-    // next value is 145;
+    // next value is 146;
 
     public static final int NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+    public static final int NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index fbb2dfc..87605f6 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -2692,6 +2692,32 @@
         addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_JOB_FINISH, name, uid);
     }
 
+    public void noteAlarmStartLocked(String name, int uid) {
+        if (!mRecordAllHistory) {
+            return;
+        }
+        uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = SystemClock.uptimeMillis();
+        if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_START, name, uid, 0)) {
+            return;
+        }
+        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_START, name, uid);
+    }
+
+    public void noteAlarmFinishLocked(String name, int uid) {
+        if (!mRecordAllHistory) {
+            return;
+        }
+        uid = mapUid(uid);
+        final long elapsedRealtime = SystemClock.elapsedRealtime();
+        final long uptime = SystemClock.uptimeMillis();
+        if (!mActiveEvents.updateState(HistoryItem.EVENT_ALARM_FINISH, name, uid, 0)) {
+            return;
+        }
+        addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_ALARM_FINISH, name, uid);
+    }
+
     private void requestWakelockCpuUpdate() {
         if (!mHandler.hasMessages(MSG_UPDATE_WAKELOCKS)) {
             Message m = mHandler.obtainMessage(MSG_UPDATE_WAKELOCKS);
@@ -2709,6 +2735,7 @@
         if (!enabled) {
             // Clear out any existing state.
             mActiveEvents.removeEvents(HistoryItem.EVENT_WAKE_LOCK);
+            mActiveEvents.removeEvents(HistoryItem.EVENT_ALARM);
             // Record the currently running processes as stopping, now that we are no
             // longer tracking them.
             HashMap<String, SparseIntArray> active = mActiveEvents.getStateForEvent(
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 7e6706c..1efa5651 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -316,7 +316,7 @@
                 final Double[] values = (Double[]) data;
                 if (values.length > level && level >= 0) {
                     return values[level];
-                } else if (level < 0) {
+                } else if (level < 0 || values.length == 0) {
                     return 0;
                 } else {
                     return values[values.length - 1];
diff --git a/core/java/com/android/internal/transition/ActionBarTransition.java b/core/java/com/android/internal/transition/ActionBarTransition.java
deleted file mode 100644
index c1065e7..0000000
--- a/core/java/com/android/internal/transition/ActionBarTransition.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.internal.transition;
-
-import android.transition.ChangeBounds;
-import android.transition.Fade;
-import android.transition.ChangeText;
-import android.transition.Transition;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.view.ViewGroup;
-
-public class ActionBarTransition {
-
-    private static boolean TRANSITIONS_ENABLED = false;
-
-    private static final int TRANSITION_DURATION = 120; // ms
-
-    private static final Transition sTransition;
-
-    static {
-        if (TRANSITIONS_ENABLED) {
-            final ChangeText tc = new ChangeText();
-            tc.setChangeBehavior(ChangeText.CHANGE_BEHAVIOR_OUT_IN);
-            final TransitionSet inner = new TransitionSet();
-            inner.addTransition(tc).addTransition(new ChangeBounds());
-            final TransitionSet tg = new TransitionSet();
-            tg.addTransition(new Fade(Fade.OUT)).addTransition(inner).
-                    addTransition(new Fade(Fade.IN));
-            tg.setOrdering(TransitionSet.ORDERING_SEQUENTIAL);
-            tg.setDuration(TRANSITION_DURATION);
-            sTransition = tg;
-        } else {
-            sTransition = null;
-        }
-    }
-
-    public static void beginDelayedTransition(ViewGroup sceneRoot) {
-        if (TRANSITIONS_ENABLED) {
-            TransitionManager.beginDelayedTransition(sceneRoot, sTransition);
-        }
-    }
-}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 88436f8..6b781c3 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -49,7 +49,6 @@
 import android.widget.SpinnerAdapter;
 import android.widget.TextView;
 import com.android.internal.R;
-import com.android.internal.transition.ActionBarTransition;
 import com.android.internal.view.menu.ActionMenuItem;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuItemImpl;
@@ -459,9 +458,6 @@
 
     public void setCustomView(View view) {
         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
-        if (showCustom) {
-            ActionBarTransition.beginDelayedTransition(this);
-        }
         if (mCustomNavView != null && showCustom) {
             removeView(mCustomNavView);
         }
@@ -499,7 +495,6 @@
     }
 
     private void setTitleImpl(CharSequence title) {
-        ActionBarTransition.beginDelayedTransition(this);
         mTitle = title;
         if (mTitleView != null) {
             mTitleView.setText(title);
@@ -519,7 +514,6 @@
     }
 
     public void setSubtitle(CharSequence subtitle) {
-        ActionBarTransition.beginDelayedTransition(this);
         mSubtitle = subtitle;
         if (mSubtitleView != null) {
             mSubtitleView.setText(subtitle);
@@ -604,7 +598,6 @@
         mDisplayOptions = options;
 
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
-            ActionBarTransition.beginDelayedTransition(this);
 
             if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
                 final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
@@ -706,7 +699,6 @@
     public void setNavigationMode(int mode) {
         final int oldMode = mNavigationMode;
         if (mode != oldMode) {
-            ActionBarTransition.beginDelayedTransition(this);
             switch (oldMode) {
             case ActionBar.NAVIGATION_MODE_LIST:
                 if (mListNavLayout != null) {
@@ -836,7 +828,6 @@
             }
         }
 
-        ActionBarTransition.beginDelayedTransition(this);
         mUpGoerFive.addView(mTitleLayout);
         if (mExpandedActionView != null ||
                 (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) {
@@ -1659,7 +1650,6 @@
 
         @Override
         public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
-            ActionBarTransition.beginDelayedTransition(ActionBarView.this);
 
             mExpandedActionView = item.getActionView();
             mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
@@ -1688,7 +1678,6 @@
 
         @Override
         public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
-            ActionBarTransition.beginDelayedTransition(ActionBarView.this);
 
             // Do this before detaching the actionview from the hierarchy, in case
             // it needs to dismiss the soft keyboard, etc.
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 0cb1f38..bfafff6 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -24,10 +24,12 @@
     boolean getBoolean(in String key, in boolean defaultValue, in int userId);
     long getLong(in String key, in long defaultValue, in int userId);
     String getString(in String key, in String defaultValue, in int userId);
-    void setLockPattern(in String pattern, int userId);
+    void setLockPattern(in String pattern, in String savedPattern, int userId);
     boolean checkPattern(in String pattern, int userId);
-    void setLockPassword(in String password, int userId);
+    byte[] verifyPattern(in String pattern, long challenge, int userId);
+    void setLockPassword(in String password, in String savedPassword, int userId);
     boolean checkPassword(in String password, int userId);
+    byte[] verifyPassword(in String password, long challenge, int userId);
     boolean checkVoldPassword(int userId);
     boolean havePattern(int userId);
     boolean havePassword(int userId);
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 2967876..123d1ac 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -280,6 +280,24 @@
     }
 
     /**
+     * Check to see if a pattern matches the saved pattern.
+     * If pattern matches, return an opaque attestation that the challenge
+     * was verified.
+     *
+     * @param pattern The pattern to check.
+     * @param challenge The challenge to verify against the pattern
+     * @return the attestation that the challenge was verified, or null.
+     */
+    public byte[] verifyPattern(List<LockPatternView.Cell> pattern, long challenge) {
+        final int userId = getCurrentOrCallingUserId();
+        try {
+            return getLockSettings().verifyPattern(patternToString(pattern), challenge, userId);
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    /**
      * Check to see if a pattern matches the saved pattern.  If no pattern exists,
      * always returns true.
      * @param pattern The pattern to check.
@@ -295,6 +313,24 @@
     }
 
     /**
+     * Check to see if a password matches the saved password.
+     * If password matches, return an opaque attestation that the challenge
+     * was verified.
+     *
+     * @param password The password to check.
+     * @param challenge The challenge to verify against the password
+     * @return the attestation that the challenge was verified, or null.
+     */
+    public byte[] verifyPassword(String password, long challenge) {
+        final int userId = getCurrentOrCallingUserId();
+        try {
+            return getLockSettings().verifyPassword(password, challenge, userId);
+        } catch (RemoteException re) {
+            return null;
+        }
+    }
+
+    /**
      * Check to see if a password matches the saved password.  If no password exists,
      * always returns true.
      * @param password The password to check.
@@ -425,8 +461,8 @@
         setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
 
         try {
-            getLockSettings().setLockPassword(null, userHandle);
-            getLockSettings().setLockPattern(null, userHandle);
+            getLockSettings().setLockPassword(null, null, userHandle);
+            getLockSettings().setLockPattern(null, null, userHandle);
         } catch (RemoteException e) {
             // well, we tried...
         }
@@ -477,24 +513,30 @@
     /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
+     * @param savedPattern The previously saved pattern, or null if none
      */
-    public void saveLockPattern(List<LockPatternView.Cell> pattern) {
-        this.saveLockPattern(pattern, getCurrentOrCallingUserId());
+    public void saveLockPattern(List<LockPatternView.Cell> pattern,
+            String savedPattern) {
+        this.saveLockPattern(pattern, savedPattern, getCurrentOrCallingUserId());
     }
 
+    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
+        this.saveLockPattern(pattern, null, userId);
+    }
     /**
      * Save a lock pattern.
      * @param pattern The new pattern to save.
+     * @param savedPattern The previously saved pattern, converted to String format
      * @param userId the user whose pattern is to be saved.
      */
-    public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
+    public void saveLockPattern(List<LockPatternView.Cell> pattern, String savedPattern, int userId) {
         try {
             if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) {
                 throw new IllegalArgumentException("pattern must not be null and at least "
                         + MIN_LOCK_PATTERN_SIZE + " dots long.");
             }
 
-            getLockSettings().setLockPattern(patternToString(pattern), userId);
+            getLockSettings().setLockPattern(patternToString(pattern), savedPattern, userId);
             DevicePolicyManager dpm = getDevicePolicyManager();
 
             // Update the device encryption password.
@@ -685,10 +727,11 @@
      * as the requested mode, but will adjust the mode to be as good as the
      * pattern.
      * @param password The password to save
+     * @param savedPassword The previously saved lock password, or null if none
      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      */
-    public void saveLockPassword(String password, int quality) {
-        saveLockPassword(password, quality, getCurrentOrCallingUserId());
+    public void saveLockPassword(String password, String savedPassword, int quality) {
+        saveLockPassword(password, savedPassword, quality, getCurrentOrCallingUserId());
     }
 
     /**
@@ -699,7 +742,8 @@
      * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      * @param userHandle The userId of the user to change the password for
      */
-    public void saveLockPassword(String password, int quality, int userHandle) {
+    public void saveLockPassword(String password, String savedPassword, int quality,
+            int userHandle) {
         try {
             DevicePolicyManager dpm = getDevicePolicyManager();
             if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) {
@@ -707,7 +751,7 @@
                         + "of length " + MIN_LOCK_PASSWORD_SIZE);
             }
 
-            getLockSettings().setLockPassword(password, userHandle);
+            getLockSettings().setLockPassword(password, savedPassword, userHandle);
             int computedQuality = computePasswordQuality(password);
 
             // Update the device encryption password.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 4a1be2d..6b44cd4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -311,6 +311,7 @@
     <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
     <protected-broadcast android:name="android.service.persistentdata.action.WIPE_IF_ALLOWED" />
 
+    <protected-broadcast android:name="android.app.action.OTA_POLICY_CHANGED" />
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -1583,6 +1584,24 @@
     <permission android:name="android.permission.WRITE_APN_SETTINGS"
         android:protectionLevel="signature|system" />
 
+    <!-- Allows an application to allow access the subscribed feeds ContentProvider.
+         @hide
+         @removed
+     -->
+    <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
+        android:label="@string/permlab_subscribedFeedsRead"
+        android:description="@string/permdesc_subscribedFeedsRead"
+        android:protectionLevel="normal" />
+
+    <!--
+        @hide
+        @removed
+    -->
+    <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
+        android:label="@string/permlab_subscribedFeedsWrite"
+        android:description="@string/permdesc_subscribedFeedsWrite"
+        android:protectionLevel="dangerous" />
+
     <!-- Allows applications to change network connectivity state -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
         android:description="@string/permdesc_changeNetworkState"
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
new file mode 100644
index 0000000..0fa82eb
--- /dev/null
+++ b/core/res/res/layout/chooser_grid.xml
@@ -0,0 +1,107 @@
+<?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.
+*/
+-->
+<com.android.internal.widget.ResolverDrawerLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:maxWidth="@dimen/resolver_max_width"
+        android:maxCollapsedHeight="256dp"
+        android:maxCollapsedHeightSmall="56dp"
+        android:id="@id/contentPanel">
+
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alwaysShow="true"
+            android:elevation="8dp"
+            android:paddingStart="?attr/dialogPreferredPadding"
+            android:background="@color/white" >
+        <ImageView android:id="@+id/title_icon"
+                   android:layout_width="24dp"
+                   android:layout_height="24dp"
+                   android:layout_gravity="start|center_vertical"
+                   android:layout_marginEnd="16dp"
+                   android:scaleType="fitCenter" />
+        <TextView android:id="@+id/title"
+                  android:layout_width="0dp"
+                  android:layout_height="wrap_content"
+                  android:layout_weight="1"
+                  android:minHeight="56dp"
+                  android:textAppearance="?attr/textAppearanceMedium"
+                  android:gravity="start|center_vertical"
+                  android:paddingEnd="?attr/dialogPreferredPadding"
+                  android:paddingTop="8dp"
+                  android:paddingBottom="8dp" />
+        <LinearLayout android:id="@+id/profile_button"
+                      android:layout_width="wrap_content"
+                      android:layout_height="48dp"
+                      android:layout_marginTop="4dp"
+                      android:layout_marginEnd="4dp"
+                      android:paddingStart="8dp"
+                      android:paddingEnd="8dp"
+                      android:paddingTop="4dp"
+                      android:paddingBottom="4dp"
+                      android:focusable="true"
+                      android:visibility="gone"
+                      style="?attr/borderlessButtonStyle">
+            <ImageView android:id="@+id/icon"
+                       android:layout_width="24dp"
+                       android:layout_height="24dp"
+                       android:layout_gravity="start|center_vertical"
+                       android:layout_marginStart="4dp"
+                       android:layout_marginEnd="16dp"
+                       android:layout_marginTop="12dp"
+                       android:layout_marginBottom="12dp"
+                       android:scaleType="fitCenter" />
+            <TextView android:id="@id/text1"
+                      android:layout_width="wrap_content"
+                      android:layout_height="wrap_content"
+                      android:layout_gravity="start|center_vertical"
+                      android:layout_marginEnd="16dp"
+                      android:textAppearance="?attr/textAppearanceButton"
+                      android:textColor="?attr/textColorPrimary"
+                      android:minLines="1"
+                      android:maxLines="1"
+                      android:ellipsize="marquee" />
+        </LinearLayout>
+    </LinearLayout>
+
+    <GridView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:id="@+id/resolver_list"
+            android:clipToPadding="false"
+            android:paddingStart="@dimen/chooser_grid_padding"
+            android:paddingEnd="@dimen/chooser_grid_padding"
+            android:scrollbarStyle="outsideOverlay"
+            android:background="@color/white"
+            android:elevation="8dp"
+            android:numColumns="4"
+            android:nestedScrollingEnabled="true" />
+
+    <TextView android:id="@+id/empty"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:layout_alwaysShow="true"
+              android:text="@string/noApplications"
+              android:padding="32dp"
+              android:gravity="center"
+              android:visibility="gone" />
+
+</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
new file mode 100644
index 0000000..664b02f
--- /dev/null
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent" android:layout_height="wrap_content"
+              android:minWidth="80dp"
+              android:gravity="center"
+              android:paddingTop="8dp"
+              android:paddingBottom="8dp"
+              android:background="?attr/activatedBackgroundIndicator">
+
+    <!-- Activity icon when presenting dialog -->
+    <ImageView android:id="@+id/icon"
+               android:layout_width="48dp"
+               android:layout_height="48dp"
+               android:scaleType="fitCenter" />
+
+    <!-- Activity name -->
+    <TextView android:id="@android:id/text1"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_marginTop="8dp"
+              android:layout_marginLeft="4dp"
+              android:layout_marginRight="4dp"
+              android:textAppearance="?attr/textAppearanceSmall"
+              android:textColor="?attr/textColorPrimary"
+              android:fontFamily="sans-serif-condensed"
+              android:gravity="center"
+              android:minLines="2"
+              android:maxLines="2"
+              android:ellipsize="marquee" />
+    <!-- Extended activity info to distinguish between duplicate activity names -->
+    <TextView android:id="@android:id/text2"
+              android:textAppearance="?android:attr/textAppearanceSmall"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_marginLeft="4dp"
+              android:layout_marginRight="4dp"
+              android:minLines="2"
+              android:maxLines="2"
+              android:gravity="center"
+              android:ellipsize="marquee" />
+</LinearLayout>
+
diff --git a/core/res/res/values-sw360dp/dimens.xml b/core/res/res/values-sw360dp/dimens.xml
new file mode 100644
index 0000000..4c74264
--- /dev/null
+++ b/core/res/res/values-sw360dp/dimens.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+    <dimen name="chooser_grid_padding">16dp</dimen>
+</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0f50502..a623d0c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2520,6 +2520,12 @@
             <enum name="rtl" value="4" />
             <!-- The paragraph direction is coming from the system Locale. -->
             <enum name="locale" value="5" />
+            <!-- The first strong directional character determines the paragraph direction. If
+                 there is no strong directional character, the paragraph direction is LTR. -->
+            <enum name="firstStrongLtr" value="6" />
+            <!-- The first strong directional character determines the paragraph direction. If
+                 there is no strong directional character, the paragraph direction is RTL. -->
+            <enum name="firstStrongRtl" value="7" />
         </attr>
 
         <!-- Defines the alignment of the text. A heuristic is used to determine the resolved
@@ -5988,11 +5994,11 @@
             <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"/>
+            <enum name="screenBased" 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"/>
+            <enum name="dpBased" value="2"/>
         </attr>
     </declare-styleable>
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 6d9bbae..8c78e74 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -23,6 +23,7 @@
     <!-- Do not translate. Defines the slots for the right-hand side icons.  That is to say, the
          icons in the status bar that are not notifications. -->
     <string-array name="config_statusBarIcons">
+       <item><xliff:g id="id">managed_profile</xliff:g></item>
        <item><xliff:g id="id">ime</xliff:g></item>
        <item><xliff:g id="id">sync_failing</xliff:g></item>
        <item><xliff:g id="id">sync_active</xliff:g></item>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2654a25..100b161 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -394,4 +394,5 @@
      <dimen name="floating_toolbar_minimum_overflow_height">192dp</dimen>
      <dimen name="floating_toolbar_overflow_width">130dp</dimen>
      <dimen name="floating_toolbar_margin">2dp</dimen>
+     <dimen name="chooser_grid_padding">0dp</dimen>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 326a1db..87c50e8 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1279,6 +1279,12 @@
     <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_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,
@@ -1655,8 +1661,8 @@
 
     <!-- On the unlock pattern screen, shown at the top of the unlock screen to tell the user what to do. Below this text is the place for theu ser to draw the pattern. -->
     <string name="lockscreen_pattern_instructions">Draw pattern to unlock</string>
-    <!-- Button at the bottom of the unlock screen to make an emergency call. -->
-    <string name="lockscreen_emergency_call">Emergency call</string>
+    <!-- Button at the bottom of the unlock screen to make an emergency call or access other emergency assistance functions. -->
+    <string name="lockscreen_emergency_call">Emergency</string>
     <!-- Button at the bottom of the unlock screen that lets the user return to a call -->
     <string name="lockscreen_return_to_call">Return to call</string>
     <!-- Shown to confirm that the user entered their lock pattern correctly. -->
@@ -3438,8 +3444,6 @@
     <string name="display_manager_overlay_display_secure_suffix">, secure</string>
 
     <!-- Keyguard strings -->
-    <!-- Label shown on emergency call button in keyguard -->
-    <string name="kg_emergency_call_label">Emergency call</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 -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 42d187d..36a736a 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2232,4 +2232,7 @@
   <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" />
+  <java-symbol type="layout" name="chooser_grid" />
+  <java-symbol type="layout" name="resolve_grid_item" />
+  <java-symbol type="id" name="title_icon" />
 </resources>
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index cf278fb..fcc6389 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -29,6 +29,10 @@
 
 public class IpPrefixTest extends TestCase {
 
+    private static InetAddress Address(String addr) {
+        return InetAddress.parseNumericAddress(addr);
+    }
+
     // Explicitly cast everything to byte because "error: possible loss of precision".
     private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
     private static final byte[] IPV6_BYTES = {
@@ -209,6 +213,34 @@
     }
 
     @SmallTest
+    public void testContains() {
+        IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
+        assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
+        assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
+        assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
+        assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
+        assertFalse(p.contains(Address("2001:4868:4860::8888")));
+        assertFalse(p.contains(null));
+        assertFalse(p.contains(Address("8.8.8.8")));
+
+        p = new IpPrefix("192.0.2.0/23");
+        assertTrue(p.contains(Address("192.0.2.43")));
+        assertTrue(p.contains(Address("192.0.3.21")));
+        assertFalse(p.contains(Address("192.0.0.21")));
+        assertFalse(p.contains(Address("8.8.8.8")));
+        assertFalse(p.contains(Address("2001:4868:4860::8888")));
+
+        IpPrefix ipv6Default = new IpPrefix("::/0");
+        assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
+        assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+
+        IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
+        assertTrue(ipv4Default.contains(Address("255.255.255.255")));
+        assertTrue(ipv4Default.contains(Address("192.0.2.1")));
+        assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+    }
+
+    @SmallTest
     public void testHashCode() {
         IpPrefix p;
         int oldCode = -1;
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 0b88bc7..831fefd 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -90,6 +90,7 @@
         assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
         assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
         assertFalse(r.matches(Address("2001:4868:4860::8888")));
+        assertFalse(r.matches(Address("8.8.8.8")));
 
         r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
         assertTrue(r.matches(Address("192.0.2.43")));
diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml
index 5c3b90b..dc364a12 100644
--- a/data/fonts/fallback_fonts.xml
+++ b/data/fonts/fallback_fonts.xml
@@ -252,6 +252,11 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansBamum-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansBatak-Regular.ttf</file>
         </fileset>
     </family>
@@ -312,11 +317,31 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansLisu-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansMandaic-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansMeeteiMayek-Regular.ttf</file>
         </fileset>
     </family>
     <family>
         <fileset>
+            <file>NotoSansNewTaiLue-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
+            <file>NotoSansNKo-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansOlChiki-Regular.ttf</file>
         </fileset>
     </family>
@@ -342,6 +367,11 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansSyriacEstrangela-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansTagbanwa-Regular.ttf</file>
         </fileset>
     </family>
@@ -362,6 +392,11 @@
     </family>
     <family>
         <fileset>
+            <file>NotoSansVai-Regular.ttf</file>
+        </fileset>
+    </family>
+    <family>
+        <fileset>
             <file>NotoSansYi-Regular.ttf</file>
         </fileset>
     </family>
@@ -411,7 +446,7 @@
         </fileset>
     </family>
     <!--
-        Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
         the East Asian punctuation for Chinese.
     -->
     <family>
@@ -419,4 +454,9 @@
             <file>NotoSansTaiLe-Regular.ttf</file>
         </fileset>
     </family>
+    <family>
+        <fileset>
+            <file>NotoSansMongolian-Regular.ttf</file>
+        </fileset>
+    </family>
 </familyset>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index f3a7647..44ea1c9 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -239,6 +239,9 @@
         <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
     </family>
     <family>
@@ -275,9 +278,21 @@
         <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
     </family>
     <family>
@@ -293,6 +308,9 @@
         <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
     </family>
     <family>
@@ -305,6 +323,9 @@
         <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
     </family>
     <family lang="zh-Hans">
@@ -335,10 +356,13 @@
         <font weight="400" style="normal">MTLmr3m.ttf</font>
     </family>
     <!--
-        Noto Sans Tai Le is intentionally kept last, to make sure it doesn't override
+        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
         the East Asian punctuation for Chinese.
     -->
     <family>
         <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
     </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
+    </family>
 </familyset>
diff --git a/docs/html-ndk/ndk/downloads/downloads_toc.cs b/docs/html-ndk/ndk/downloads/downloads_toc.cs
new file mode 100644
index 0000000..66d0007
--- /dev/null
+++ b/docs/html-ndk/ndk/downloads/downloads_toc.cs
@@ -0,0 +1,21 @@
+<?cs # Table of contents for Dev Guide.
+
+       For each document available in translation, add an localized title to this TOC.
+       Do not add localized title for docs not available in translation.
+       Below are template spans for adding localized doc titles. Please ensure that
+       localized titles are added in the language order specified below.
+?>
+
+
+<ul id="nav">
+  <li><a href="/ndk/downloads/index.html"><span class="en">NDK Download</span></a></li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html-ndk/ndk/downloads/index.jd b/docs/html-ndk/ndk/downloads/index.jd
new file mode 100644
index 0000000..ef00069
--- /dev/null
+++ b/docs/html-ndk/ndk/downloads/index.jd
@@ -0,0 +1,4 @@
+page.title=NDK Downloads
+@jd:body
+
+<p>downloads
\ No newline at end of file
diff --git a/docs/html-ndk/ndk/guides/guides_toc.cs b/docs/html-ndk/ndk/guides/guides_toc.cs
new file mode 100644
index 0000000..e6bc199
--- /dev/null
+++ b/docs/html-ndk/ndk/guides/guides_toc.cs
@@ -0,0 +1,22 @@
+<?cs # Table of contents for Dev Guide.
+
+       For each document available in translation, add an localized title to this TOC.
+       Do not add localized title for docs not available in translation.
+       Below are template spans for adding localized doc titles. Please ensure that
+       localized titles are added in the language order specified below.
+?>
+
+
+<ul id="nav">
+  <li><a href="/ndk/guides/index.html"><span class="en">Getting Started</span></a></li>
+  <li><a href="/ndk/guides/pg_html/md_1__concepts__concepts.html">Concepts</a></li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html-ndk/ndk/guides/index.jd b/docs/html-ndk/ndk/guides/index.jd
new file mode 100644
index 0000000..8c3ecab
--- /dev/null
+++ b/docs/html-ndk/ndk/guides/index.jd
@@ -0,0 +1,4 @@
+page.title=Concepts
+@jd:body
+
+<p>To use the NDK, you must download it and install it separately from the SDK. To do so, follow these directions.
\ No newline at end of file
diff --git a/docs/html-ndk/ndk/guides/md_1__concepts__concepts.html b/docs/html-ndk/ndk/guides/md_1__concepts__concepts.html
new file mode 100644
index 0000000..2dcf6ae
--- /dev/null
+++ b/docs/html-ndk/ndk/guides/md_1__concepts__concepts.html
@@ -0,0 +1,4 @@
+page.title=Concepts
+@jd:body
+
+<p>This section provides a high-level explanation of how the NDK works. The Android NDK is a set of tools allowing you to embed C or C++ (“native code”) into your Android apps. The ability to use native code in Android apps can be particularly useful to developers who wish to do one or more of the following:
\ No newline at end of file
diff --git a/docs/html-ndk/ndk/index.jd b/docs/html-ndk/ndk/index.jd
new file mode 100644
index 0000000..f1c5ce6
--- /dev/null
+++ b/docs/html-ndk/ndk/index.jd
@@ -0,0 +1,15 @@
+fullpage=true
+page.viewport_width=970
+excludeFromSuggestions=true
+page.metaDescription=The official Android NDK developer web site.
+page.customHeadTag=<meta name="google-site-verification" content="sa-bIAI6GKvct3f61-WpRguHq-aNjtF7xJjMTSi79as" />
+
+@jd:body
+
+
+<h1>SUPER FANCY NDK LANDING PAGE<h1>
+
+<p>Welcome to the placeholder text for the NDK. Here, you'll find all of the details you need to
+combine the power of native code with Android flexibility and compatibility. The documents here
+help you get started, introduce some key concepts that you should know when using the NDK, and then
+provide a variety of other information that you'll find helpful while developing your app.</p>
diff --git a/docs/html-ndk/ndk/reference/index.jd b/docs/html-ndk/ndk/reference/index.jd
new file mode 100644
index 0000000..a496f19
--- /dev/null
+++ b/docs/html-ndk/ndk/reference/index.jd
@@ -0,0 +1,4 @@
+page.title=Reference
+@jd:body
+
+<p>NDK reference docs
\ No newline at end of file
diff --git a/docs/html-ndk/ndk/reference/reference_toc.cs b/docs/html-ndk/ndk/reference/reference_toc.cs
new file mode 100644
index 0000000..01364a6
--- /dev/null
+++ b/docs/html-ndk/ndk/reference/reference_toc.cs
@@ -0,0 +1,21 @@
+<?cs # Table of contents for Dev Guide.
+
+       For each document available in translation, add an localized title to this TOC.
+       Do not add localized title for docs not available in translation.
+       Below are template spans for adding localized doc titles. Please ensure that
+       localized titles are added in the language order specified below.
+?>
+
+
+<ul id="nav">
+  <li><a href="/ndk/reference/index.html"><span class="en">foo.h</span></a></li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html-ndk/ndk/samples/index.jd b/docs/html-ndk/ndk/samples/index.jd
new file mode 100644
index 0000000..b333aa7
--- /dev/null
+++ b/docs/html-ndk/ndk/samples/index.jd
@@ -0,0 +1,4 @@
+page.title=Samples
+@jd:body
+
+<p>NDK samples
\ No newline at end of file
diff --git a/docs/html-ndk/ndk/samples/samples_toc.cs b/docs/html-ndk/ndk/samples/samples_toc.cs
new file mode 100644
index 0000000..9fb036e
--- /dev/null
+++ b/docs/html-ndk/ndk/samples/samples_toc.cs
@@ -0,0 +1,21 @@
+<?cs # Table of contents for Dev Guide.
+
+       For each document available in translation, add an localized title to this TOC.
+       Do not add localized title for docs not available in translation.
+       Below are template spans for adding localized doc titles. Please ensure that
+       localized titles are added in the language order specified below.
+?>
+
+
+<ul id="nav">
+  <li><a href="/ndk/samples/index.html"><span class="en">Stuff</span></a></li>
+</ul>
+
+
+<script type="text/javascript">
+<!--
+    buildToggleLists();
+    changeNavLang(getLangPref());
+//-->
+</script>
+
diff --git a/docs/html/distribute/googleplay/families/about.jd b/docs/html/distribute/googleplay/families/about.jd
new file mode 100644
index 0000000..c542e0f
--- /dev/null
+++ b/docs/html/distribute/googleplay/families/about.jd
@@ -0,0 +1,67 @@
+page.title=Designed for Families
+page.metaDescription=Designed for Families helps you make your apps and games more discoverable to families.
+page.image=/distribute/images/about-dff-sm.jpg
+meta.tags="families, googleplay, distribution"
+page.tags="families"
+
+@jd:body
+
+<p>
+  In several weeks, a new family-focused experience on Google Play will give
+  users new ways to browse, search, and discover high quality apps and games
+  for their families.
+</p>
+
+<p>
+  To support a more family-friendly store, developers are invited to opt-in
+  family-focused apps and games to the new Designed for Families program. Apps
+  that meet the <a href=
+  "https://support.google.com/googleplay/android-developer/answer/6184502">program
+  requirements</a> will be shown in the new family experience so that
+  parents can find suitable, trusted, high-quality apps and games more easily.
+</p>
+
+<img src="{@docRoot}distribute/images/about-dff-sm.jpg">
+
+<p>
+  Opt-in your apps and games today using the tools and processes you currently
+  use to manage your apps in the Developer Console. Your apps in the program
+  can benefit from enhanced discoverability in addition to maintaining their
+  existing categories, rankings, and reviews elsewhere on the Google Play
+  store.
+</p>
+
+<h2 id="elibibility">Eligibility</h2>
+
+<p>
+  Apps in the family-friendly experience on Google Play will be more
+  discoverable by parents and families, who expect the apps to be age
+  appropriate. The Designed for Families program is designed to be inclusive of
+  apps that are made for kids as well as those that can be enjoyed by the
+  entire family. To address this audience, there are specific guidelines and
+  policies your apps need to meet, which will be assessed in an app content
+  review.
+</p>
+
+<p>
+  Make sure that you're familiar with the policies that your app must comply
+  with. These include <a href=
+  "http://play.google.com/about/developer-content-policy.html">content
+  policies</a>, the <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html">Developer
+  Distribution Agreement</a>, and the <a href=
+  "https://play.google.com/intl/ALL_us/about/families/developer-distribution-agreement-addendum.html">
+  Designed for Families DDA Addendum</a>.
+</p>
+
+<p>
+  Your app must also meet the <a href=
+  "https://support.google.com/googleplay/android-developer/answer/6184502">Designed
+  for Families program requirements</a> listed in the Google Play Developer
+  Help Center.
+</p>
+
+<div class="paging-links" style="padding-top:.75em;">
+  <a href="{@docRoot}distribute/googleplay/families/start.html" class=
+  "next-class-link">Next: Opt-In</a>
+</div>
diff --git a/docs/html/distribute/googleplay/families/faq.jd b/docs/html/distribute/googleplay/families/faq.jd
new file mode 100644
index 0000000..c6fbf86
--- /dev/null
+++ b/docs/html/distribute/googleplay/families/faq.jd
@@ -0,0 +1,336 @@
+page.title=Frequently Asked Questions
+meta.tags="families", "guidelines", "quality"
+page.tags="families", "addendum"
+page.metaDescription=Questions and answers about Designed for Families
+
+@jd:body
+
+    <style>
+  dt {
+    font-weight:bold;
+  }
+  </style>
+  
+<div id="qv-wrapper">
+<ol id="qv">
+<h2>In this document</h2>
+<ol>
+  <li><a href="#review">App Review and Opt-In</a></li>
+  <li><a href="#monetization">Monetization</a></li>
+  <li><a href="#other">Other Questions</a></li>
+</ol>
+</div>
+
+<p>
+  The sections below provide more information about Designed for Families
+  and answer common questions that you might have about it.
+</p>
+
+
+<h2 id="review">App Review and Opt-In</h2>
+
+<dl>
+<dt>How do I opt-in my app(s)?</dt>
+
+<dl>
+  <dd>
+    You can opt-in to Designed for Families on the Pricing and Distribution tab
+    for your app on the Google Play Developer Console. Here's a <a href=
+    "{@docRoot}distribute/googleplay/families/start.html">step-by-step
+    walkthrough</a>.
+  </dd>
+
+  <dt>
+    Where do I disclose my app’s interactive features? Why are you collecting
+    this information?
+  </dt>
+
+  <dd>
+    Interactive feature disclosures are part of the content rating
+    questionnaire. You have an opportunity to review your disclosures as
+    part of the Designed for Families program opt-in flow. We collect this
+    information so that users can make informed choices when evaluating your
+    app.
+  </dd>
+
+  <dt>
+    What is COPPA?
+  </dt>
+
+  <dd>
+    COPPA is the Federal Trade Commission’s (FTC) Child Online Privacy
+    Protection Rule. More details are available on the <a
+    href="http://www.ftc.gov/tips-advice/business-center/guidance/complying-coppa-frequently-asked-questions">
+    FTC's FAQ about COPPA</a>. Note that Google Play cannot provide legal guidance to developers
+    on how to comply with COPPA or other child statutes.
+  </dd>
+
+  <dt>
+    Do I need to provide an up-to-date privacy policy and where do I do that?
+  </dt>
+
+  <dd>
+    Yes, you need to provide a link to a persistent privacy policy on your
+    app’s store listing and confirm your compliance with local privacy statutes
+    in the Developer Console. To add or review your privacy policy, choose your
+    app in the Developer Console and then scroll to the bottom of the
+    <strong>Store Listing</strong> section.
+  </dd>
+
+  <dt>
+    How many age groups can I select?
+  </dt>
+
+  <dd>
+    You can select up to two adjacent age groups. Age groups are: Ages 5 &
+    Under, Ages 6-8, and Ages 9-12. However, if your app targets audiences
+    comprised of children and older audiences, you must select the <em>General
+    Audience</em> category.
+  </dd>
+
+  <dt>
+    How many content categories can I select in the Designed for Families
+    program?
+  </dt>
+
+  <dd>
+    You can select one category as part of the Designed for Families program
+    and another category for the general Google Play store.
+  </dd>
+
+  <dt>
+    What are the Designed for Families categories?
+  </dt>
+
+<ul>
+<li><strong>Action & Adventure</strong>: These are action-oriented apps/games and include everything
+  from racing games, fairy tale adventures, and more.
+  </li>
+
+  <li style="list-style: none"><strong>Brain Games</strong>: This category includes games that
+  make the user think and includes puzzles, matching games, and similar
+  games.
+  </li>
+
+  <li><strong>Creativity</strong>: These are apps/games that spur creativity.
+  Example types of apps/games we expect in this category include drawing,
+  painting, and other games where you can build things.
+  </li>
+
+  <li><strong>Education</strong>: These are apps/games that have educational value and include
+  math, science, learning the alphabet, learning to count, and many more types of
+  educational content like geography and history.
+  </li>
+
+  <li><strong>Music and Video</strong>: These are apps/games that contain a musical element or
+  video component and include everything from playing the
+  piano to watching videos and more.
+  </li>
+
+  <li><strong>Pretend Play</strong>: These are apps/games where one can pretend to take on a
+  role, like pretending to be a cook or a doctor.
+  </li>
+</ul>
+
+<dl>
+  <dt>
+    Will it take longer for my app to get published if I opt-in to the Designed
+    for Families program?
+  </dt>
+
+  <dd>
+    When you opt-in to Designed for Families, Google Play reviews your app to
+    confirm that it is appropriate for families. Assuming your app complies with all program
+    requirements, we expect that publishing time should not take any longer
+    than normal; however, there may be a delay in publishing the app if it is
+    rejected during the Designed for Families review. 
+  </dd>
+
+  <dt>
+    What happens if my app is rejected from the Designed for Families program?
+  </dt>
+
+  <dd>
+    If your app is rejected from the Designed for Families program, we’ll
+    indicate why in the Developer Console and in a detailed email. You’ll have
+    an opportunity to correct the issues and resubmit your app to the program,
+    or change your opt-in response. Note that if you have an existing app that
+    is live on Google Play, only your app update will be rejected (your app
+    will remain live on the Play store). If you’ve submitted a new app to the
+    Designed for Families program that does not meet the requirements, your
+    entire app submission will be rejected and the app will not be published on
+    Play. You can then address the identified issue(s) and resubmit the app for
+    the Designed for Families program or opt-out of the program.
+  </dd>
+
+  <dt>
+    What happens if my app is found to be non-compliant with Designed for
+    Families program requirements after it has been published?
+  </dt>
+
+  <dd>
+    Your app may be removed or suspended from the Google Play Store, not only
+    the Designed for Families program. Removed apps can follow the same
+    remedies as rejected apps. Suspended apps can be appealed using the
+    developer appeal process.
+  </dd>
+
+  <dt>
+    If I opt-in to the Designed for Families program, can I opt-out later on?
+  </dt>
+
+  <dd>
+    Yes, you may opt-out of the program at any time. Please note that by opting
+    out you would lose your placement in the new family-friendly experience as
+    well as the other benefits of the program.
+  </dd>
+
+  <dt>
+    What happens when I update my app after it has been accepted into the
+    program?
+  </dt>
+
+  <dd>
+    Apps that are part of the Designed for Families program need to maintain
+    compliance with the eligibility requirements at all times. If you need to
+    edit the Designed for Families metadata associated with your app, please go
+    to the Pricing & Distribution section of the Google Play Developer Console
+    to edit this information. If updating your app results in you changing your
+    target audience, we recommend that you alert the users who already
+    have your app installed.
+  </dd>
+
+  <dt>
+    Can apps and games that use Google sign-in or Google Play Game
+    services opt-into the Designed for Families program?
+  </dt>
+
+  <dd>
+    Apps that participate in Designed for Families that are wholly
+    child-focused, i.e. that target the following age groups: Ages 5 & Under,
+    Ages 6 to 8, or Ages 9 to 12 <strong>may not</strong> use Google+ Sign-in
+    or Google Play Game services as the login experience for their
+    application.
+
+    <p>
+      Apps that participate in Designed for Families that target both children and
+      older audiences, can use Google+ Sign-in or Google Play Game services as an
+      <strong>optional</strong> feature. Child users must be able to access the app
+      or game in its entirety without signing into Google+ or Google Play Game services.
+    </p>
+  </dd>
+
+  <dt>
+    My app is opted-in to Google Play for Education and has Google sign-in integration
+    so that students can login with their school accounts. Do I need to change the way
+    Google sign-in works in my app?
+   </dt>
+
+  <dd>
+    Apps that participate in Google Play for Education may use Google sign-in for
+    student accounts as long as it is not a blocking requirement for all users of the app.
+  </dd>
+</dl>
+
+<h2 id="monetization">
+  Designed for Families Program Monetization
+</h2>
+
+<dl>
+  <dt>
+    Can you give me more details on the advertising policies for Designed for
+    Families?
+  </dt>
+
+  <dd>
+    Read the <a href=
+    "https://support.google.com/googleplay/android-developer/answer/6184502#ads">
+    ads policy for Designed for Families</a>.
+  </dd>
+
+  <dt>
+    Can my app serve interstitial advertisements?
+  </dt>
+
+  <dd>
+    Interstitial ads may be appropriate for some apps. However, a user must be
+    able to navigate to the main activity before any ads are served.
+  </dd>
+
+  <dt>
+    How do I know that my ad network complies with the advertising
+    policies for Designed for Families?
+  </dt>
+
+  <dd>
+    Please contact your advertising network to ask them about their content policies
+    and advertising practices. If you use AdMob, then please refer to the <a href=
+    "https://support.google.com/admob/answer/3248194">AdMob help center</a> for
+    details on how to tag your app or a specific ad unit for child-directed
+    treatment. It is the developer’s responsibility to ensure that the overall
+    user experience with in-app advertising meets the <a href=
+    "https://support.google.com/googleplay/android-developer/answer/6184502">Designed
+    for Families program requirements</a>.
+  </dd>
+
+  <dt>
+    Can I have in-app purchases in my app?
+  </dt>
+
+  <dd>
+    There are no specific restrictions relating to in-app purchases (IAP) in
+    apps participating in the Designed for Families program other than
+    compliance with the <a href=
+    "https://play.google.com/intl/ALL_us/about/families/developer-distribution-agreement-addendum.html">
+    Designed for Families DDA</a> and other applicable legal requirements, but
+    Play reserves the right to reject apps for overly aggressive commercial
+    tactics. Google Play will enforce IAP password protection on all apps
+    participating in the Designed for Families program that primarily target
+    child audiences to ensure that parents, not children, are approving
+    purchases. Please note that this treatment does not extend to apps
+    targeting general audiences.
+  </dd>
+</dl>
+
+<h2 id="other">
+  Other Questions
+</h2>
+
+<dl>
+  <dt>
+    Who is the intended target audience for participating Designed for Families
+    apps?
+  </dt>
+
+  <dd>
+    Our goal is to provide a great experience on the Google Play store for
+    parents and guardians to discover delightful apps designed for kids and
+    families from trusted brands and developers.
+  </dd>
+
+  <dt>
+    Is the Designed for Families Program only available to developers in
+    certain countries?
+  </dt>
+
+  <dd>
+    Designed for Families is a global program.
+  </dd>
+
+  <dt>
+    What happens to apps that are published in the current Family Games
+    category?
+  </dt>
+
+  <dd>
+    The current Family Games category will be deprecated in May 2015. Apps
+    currently in the Family Games category will have to select
+    a different category in the Play store. Apps that have not selected another
+    category will be assigned to the Casual Games category.
+  </dd>
+</dl>
+
+<div class="paging-links" style="padding-top:.75em;">
+  <a href="https://docs.google.com/forms/d/1EtvUWqlkxS6RxHJjeI-3-7uzdbIZx6n9Cocy2D369B8/viewform" class=
+  "next-class-link">Next: Stay in Touch</a>
+</div>
\ No newline at end of file
diff --git a/docs/html/distribute/googleplay/families/start.jd b/docs/html/distribute/googleplay/families/start.jd
new file mode 100644
index 0000000..af4eb3a
--- /dev/null
+++ b/docs/html/distribute/googleplay/families/start.jd
@@ -0,0 +1,114 @@
+page.title=Opt-In to Designed for Families
+meta.tags="families", "guidelines", "quality"
+page.tags="families", "addendum"
+page.metaDescription=Join Designed for Families in just a few simple steps.
+
+@jd:body
+
+<p>
+  If you're building an app designed for kids and families, there are a few
+  things you need to do <em>before</em> you’ll be ready to opt-in to the Designed for
+  Families program:
+</p>
+
+<ul>
+  <li>Complete the content rating questionnaire for your app and meet an ESRB
+  rating of Everyone or Everyone 10+ rating
+  </li>
+
+  <li>Add a privacy policy link to your app’s <strong>Store Listing</strong>
+  page.
+  </li>
+
+  <li>Make sure your app meets all the <a href=
+  "https://support.google.com/googleplay/android-developer/answer/6184502">Designed
+  for Families program requirements.</a>
+  </li>
+</ul>
+
+<p>
+  Now that your app is ready to publish, you can opt-in to Designed for
+  Families directly from the <a href=
+  "https://play.google.com/apps/publish/">Developer Console</a>. Opt-in means
+  that you want your app to be made available on the new family-friendly
+  experience on Google Play in addition to the category you’ve selected on
+  the Google Play Store.
+</p>
+
+<p>
+  Opt-in also confirms that your app complies with <a href=
+  "http://play.google.com/about/developer-content-policy.html">Google Play
+  Developer Program Policies</a> and the <a href=
+  "http://play.google.com/about/developer-distribution-agreement.html">Developer
+  Distribution Agreement</a>, including the <a href=
+  "https://play.google.com/intl/ALL_us/about/families/developer-distribution-agreement-addendum.html">
+  Designed for Families DDA Addendum</a>. If you are not familiar with these
+  policy documents or the Addendum, make sure to read them before opting-in.
+</p>
+
+<p>
+  Once you're ready, here's how to opt-in to Designed for Families for a specific app:
+</p>
+
+<ol>
+<li>In the Developer Console <strong>All Applications</strong> page, click the app you want to
+  opt-in. Under Pricing and Distribution, scroll down to find <strong>Designed for
+  Families</strong> and the opt-in checkbox.<img src="/images/gp-dff-optin.png" style=
+  "border:2px solid #ddd;margin:1em 0;">
+  </li>
+
+  <li>Start the opt-in flow and confirm that your app meets the eligibility
+  requirements.</li>
+  <li>If your app has ads, confirm that it meets the ads policy.
+  <img src="/images/gp-dff-appinfo.png"
+  style="border:2px solid #ddd;margin:1em 0;"></li>
+  <li>Choose your target age groups from: Ages 5 & Under, Ages 6 to 8, Ages 9
+  to 12, or General Audience (for apps which target children and older
+  audiences). If your app targets more than one age group, you can choose up to
+  two adjacent age groups. Apps with an ESRB 10+ rating can only choose an
+  age target of 9-12 or General Audience.
+  </li>
+
+  <li>Choose a category for your app for the new family-focused experience on
+  Google Play. Your app will also be discoverable in its existing category in
+  Google Play.</li>
+  <li>Review and agree to the linked documents and then click
+  <strong>Opt-In</strong>. Finally, click <strong>Submit update</strong> on the
+  Pricing & Distribution page to publish or update your app.
+  </li>
+</ol>
+
+<p>
+  Once you opt-in your app, it will be thoroughly reviewed before being
+  accepted into the Designed for Families program.
+</p>
+
+<p class="note">
+  <strong>Note</strong>: Published apps in the Designed for Families program
+  are also available to all users on Google Play. 
+</p>
+
+<p>
+  If you opt-in an app that you're publishing for the first time and it doesn't
+  meet the Designed for Families program requirements, it won't be made available
+  on Google Play until <strong>either</strong> you update the app to meet the
+  program requirements <strong>or</strong> you uncheck the opt-in box and pass
+  Google Play's standard review process.
+</p>
+
+<p>
+  If you opt-in an app that's already published on Google Play and it doesn't
+  meet the program requirements, it will remain available to all users but won't
+  be added to the new family experience until you update the app to meet the
+  program requirements.
+</p>
+
+<p>
+  If you publish an update to an app that's opted-in to Designed for Families,
+  the app update needs to pass the Designed for Families review before it will
+  become available to all users on Google Play.</p>
+
+<div class="paging-links" style="padding-top:.75em;">
+  <a href="{@docRoot}distribute/googleplay/families/faq.html" class=
+  "next-class-link">Next: Frequently Asked Questions</a>
+</div>
diff --git a/docs/html/distribute/googleplay/googleplay_toc.cs b/docs/html/distribute/googleplay/googleplay_toc.cs
index 594d6d6..78a3731 100644
--- a/docs/html/distribute/googleplay/googleplay_toc.cs
+++ b/docs/html/distribute/googleplay/googleplay_toc.cs
@@ -24,8 +24,8 @@
     </div>
   </li>
   <li class="nav-section">
-    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/auto.html">
-          <span class="en">Distributing to <span style="white-space:nowrap">Android Auto</span></span>
+    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/wear.html">
+          <span class="en">Distributing to <span style="white-space:nowrap">Android Wear</span></span>
         </a>
     </div>
   </li>
@@ -36,12 +36,29 @@
     </div>
   </li>
   <li class="nav-section">
-    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/wear.html">
-          <span class="en">Distributing to <span style="white-space:nowrap">Android Wear</span></span>
+    <div class="nav-section-header empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/auto.html">
+          <span class="en">Distributing to <span style="white-space:nowrap">Android Auto</span></span>
         </a>
     </div>
   </li>
   <li class="nav-section">
+    <div class="nav-section-header" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/families/about.html">
+          <span class="en">Designed for Families</span>
+        </a>
+    </div>
+    <ul>
+      <li><a href="<?cs var:toroot?>distribute/googleplay/families/start.html">
+          <span class="en">Opt-In</span>
+        </a></li>
+      <li><a href="<?cs var:toroot?>distribute/googleplay/families/faq.html">
+          <span class="en">FAQ</span>
+        </a></li>
+      <li><a href="https://docs.google.com/forms/d/1EtvUWqlkxS6RxHJjeI-3-7uzdbIZx6n9Cocy2D369B8/viewform">
+          <span class="en">Stay in Touch »</span>
+        </a></li>
+    </ul>
+  </li>
+  <li class="nav-section">
     <div class="nav-section-header" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/googleplay/edu/about.html">
           <span class="en">Google Play for Education</span>
         </a>
@@ -56,7 +73,6 @@
     </ul>
   </li>
 </ul>
-
 <script type="text/javascript">
 <!--
     buildToggleLists();
diff --git a/docs/html/distribute/googleplay/index.jd b/docs/html/distribute/googleplay/index.jd
index 20f07fa..b25f6b75 100644
--- a/docs/html/distribute/googleplay/index.jd
+++ b/docs/html/distribute/googleplay/index.jd
@@ -26,7 +26,7 @@
   <div class="resource-widget resource-flow-layout landing col-16"
     data-query="collection:distribute/gp/gpfelanding"
     data-cardSizes="6x6"
-    data-maxResults="3">
+    data-maxResults="5">
   </div>
 
   <h3>Related resources</h3>
diff --git a/docs/html/distribute/images/about-dff-sm.jpg b/docs/html/distribute/images/about-dff-sm.jpg
new file mode 100644
index 0000000..10cc5fa
--- /dev/null
+++ b/docs/html/distribute/images/about-dff-sm.jpg
Binary files differ
diff --git a/docs/html/images/gp-dff-appinfo.png b/docs/html/images/gp-dff-appinfo.png
new file mode 100644
index 0000000..30f58b8
--- /dev/null
+++ b/docs/html/images/gp-dff-appinfo.png
Binary files differ
diff --git a/docs/html/images/gp-dff-optin.png b/docs/html/images/gp-dff-optin.png
new file mode 100644
index 0000000..9f97d2d
--- /dev/null
+++ b/docs/html/images/gp-dff-optin.png
Binary files differ
diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js
index 05a8a3e..99b9dd1 100644
--- a/docs/html/jd_collections.js
+++ b/docs/html/jd_collections.js
@@ -87,7 +87,8 @@
       "distribute/googleplay/auto.html",
       "distribute/googleplay/tv.html",
       "distribute/googleplay/wear.html",
-      "distribute/googleplay/edu/about.html"
+      "distribute/googleplay/edu/about.html",
+      "distribute/googleplay/families/about.html"
     ]
   },
   "distribute/essentials": {
diff --git a/docs/html/tools/debugging/debugging-memory.jd b/docs/html/tools/debugging/debugging-memory.jd
index ae67b3c..5893ad1 100644
--- a/docs/html/tools/debugging/debugging-memory.jd
+++ b/docs/html/tools/debugging/debugging-memory.jd
@@ -24,63 +24,72 @@
 
 
 <p>Because Android is designed for mobile devices, you should always be careful about how much
-random-access memory (RAM) your app uses. Although Android’s Dalvik virtual machine performs
-routine garbage collection, this doesn’t mean you can ignore when and where your app allocates and
+random-access memory (RAM) your application uses. Although Dalvik and ART perform
+routine garbage collection (GC), this doesn’t mean you can ignore when and where your application allocates and
 releases memory. In order to provide a stable user experience that allows the system to quickly
-switch between apps, it’s important that your app does not needlessly consume memory when the user
+switch between apps, it is important that your application does not needlessly consume memory when the user
 is not interacting with it.</p>
 
 <p>Even if you follow all the best practices for <a href="{@docRoot}training/articles/memory.html"
 >Managing Your App Memory</a> during
 development (which you should), you still might leak objects or introduce other memory bugs. The
-only way to be certain your app is using as little memory as possible is to analyze your app’s
+only way to be certain your application is using as little memory as possible is to analyze your app’s
 memory usage with tools. This guide shows you how to do that.</p>
 
 
 <h2 id="LogMessages">Interpreting Log Messages</h2>
 
-<p>The simplest place to begin investigating your apps memory usage is the Dalvik log messages. You'll
-find these log messages in <a href="{@docRoot}tools/help/logcat.html">logcat</a> (the output is
-available in the Device Monitor or directly in IDEs such as Eclipse and Android Studio).</p>
+<p>The simplest place to begin investigating your application’s memory usage is the runtime log messages.
+Sometimes when a GC occurs, a message is printed to
+<a href="{@docRoot}tools/help/logcat.html">logcat</a>. The logcat output is also available in the
+Device Monitor or directly in IDEs such as Eclipse and Android Studio.</p>
 
-<p>Every time a garbage collection occurs, logcat prints a message with the following information:</p>
+<h3 id="DalvikLogMessages">Dalvik Log Messages</h3>
+
+<p>In Dalvik (but not ART), every GC prints the following information to logcat:</p>
 
 <pre class="no-pretty-print">
 D/dalvikvm: &lt;GC_Reason> &lt;Amount_freed>, &lt;Heap_stats>, &lt;External_memory_stats>, &lt;Pause_time>
 </pre>
 
+<p>Example:</p>
+
+<pre class="no-pretty-print">
+D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
+</pre>
+
 <dl>
 <dt>GC Reason</dt>
 <dd>
-What triggered the garbage collection and what kind of collection it is. Reasons that may appear
+What triggered the GC and what kind of collection it is. Reasons that may appear
 include:
 <dl>
 <dt><code>GC_CONCURRENT</code></dt>
-<dd>A concurrent garbage collection that frees up memory as your heap begins to fill up.</dd>
+<dd>A concurrent GC that frees up memory as your heap begins to fill up.</dd>
 
 <dt><code>GC_FOR_MALLOC</code></dt>
-<dd>A garbage collection caused because your app attempted to allocate memory when your heap was
-already full, so the system had to stop your app and reclaim memory.</dd>
+<dd>A GC caused because your application attempted to allocate memory when your heap was
+already full, so the system had to stop your application and reclaim memory.</dd>
 
 <dt><code>GC_HPROF_DUMP_HEAP</code></dt>
-<dd>A garbage collection that occurs when you create an HPROF file to analyze your heap.</dd>
+<dd>A GC that occurs when you request to create an HPROF file to analyze your heap.</dd>
 
 <dt><code>GC_EXPLICIT</code>
-<dd>An explicit garbage collection, such as when you call {@link java.lang.System#gc()} (which you
-should avoid calling and instead trust the garbage collector to run when needed).</dd>
+<dd>An explicit GC, such as when you call {@link java.lang.System#gc()} (which you
+should avoid calling and instead trust the GC to run when needed).</dd>
 
 <dt><code>GC_EXTERNAL_ALLOC</code></dt>
 <dd>This happens only on API level 10 and lower (newer versions allocate everything in the Dalvik
-heap). A garbage collection for externally allocated memory (such as the pixel data stored in
+heap). A GC for externally allocated memory (such as the pixel data stored in
 native memory or NIO byte buffers).</dd>
 </dl>
 </dd>
 
 <dt>Amount freed</dt>
-<dd>The amount of memory reclaimed from this garbage collection.</dd>
+<dd>The amount of memory reclaimed from this GC.</dd>
 
 <dt>Heap stats</dt>
-<dd>Percentage free and (number of live objects)/(total heap size).</dd>
+<dd>Percentage free of the heap and (number of live objects)/(total heap size).</dd>
 
 <dt>External memory stats</dt>
 <dd>Externally allocated memory on API level 10 and lower (amount of allocated memory) / (limit at
@@ -91,20 +100,141 @@
 beginning of the collection and another near the end.</dd>
 </dl>
 
-<p>For example:</p>
+<p>As these log messages accumulate, look out for increases in the heap stats (the
+{@code 3571K/9991K} value in the above example). If this value continues to increase, you may have
+a memory leak.</p>
+
+
+<h3 id="ARTLogMessages">ART Log Messages</h3>
+
+<p>Unlike Dalvik, ART doesn't log messqages for GCs that were not explicity requested. GCs are only
+printed when they are they are deemed slow. More precisely, if the GC pause exceeds than 5ms or
+the GC duration exceeds 100ms. If the application is not in a pause perceptible process state,
+then none of its GCs are deemed slow. Explicit GCs are always logged.</p>
+
+<p>ART includes the following information in its garbage collection log messages:</p>
 
 <pre class="no-pretty-print">
-D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
+I/art: &lt;GC_Reason> &lt;GC_Name> &lt;Objects_freed>(&lt;Size_freed>) AllocSpace Objects, &lt;Large_objects_freed>(&lt;Large_object_size_freed>) &lt;Heap_stats> LOS objects, &lt;Pause_time(s)>
 </pre>
 
-<p>As these log messages stack up, look out for increases in the heap stats (the
-{@code 3571K/9991K} value in the above example). If this value
-continues to increase and doesn't ever seem to get smaller, you could have a memory leak.</p>
+<p>Example:</p>
 
+<pre class="no-pretty-print">
+I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms
+</pre>
+
+<dl>
+<dt>GC Reason</dt>
+<dd>
+What triggered the GC and what kind of collection it is. Reasons that may appear
+include:
+<dl>
+<dt><code>Concurrent</code></dt>
+<dd>A concurrent GC which does not suspend application threads. This GC runs in a background thread
+and does not prevent allocations.</dd>
+
+<dt><code>Alloc</code></dt>
+<dd>The GC was initiated because your application attempted to allocate memory when your heap
+was already full. In this case, the garbage collection occurred in the allocating thread.</dd>
+
+<dt><code>Explicit</code>
+<dd>The garbage collection was explicitly requested by an application, for instance, by
+calling {@link java.lang.System#gc()} or {@link java.lang.Runtime#gc()}. As with Dalvik, in ART it is
+recommended that you trust the GC and avoid requesting explicit GCs if possible. Explicit GCs are
+discouraged since they block the allocating thread and unnecessarily was CPU cycles. Explicit GCs
+could also cause jank if they cause other threads to get preempted.</dd>
+
+<dt><code>NativeAlloc</code></dt>
+<dd>The collection was caused by native memory pressure from native allocations such as Bitmaps or
+RenderScript allocation objects.</dd>
+
+<dt><code>CollectorTransition</code></dt>
+<dd>The collection was caused by a heap transition; this is caused by switching the GC at run time.
+Collector transitions consist of copying all the objects from a free-list backed
+space to a bump pointer space (or visa versa). Currently collector transitions only occur when an
+application changes process states from a pause perceptible state to a non pause perceptible state
+(or visa versa) on low RAM devices.
+</dd>
+
+<dt><code>HomogeneousSpaceCompact</code></dt>
+<dd>Homogeneous space compaction is free-list space to free-list space compaction which usually
+occurs when an application is moved to a pause imperceptible process state. The main reasons for doing
+this are reducing RAM usage and defragmenting the heap.
+</dd>
+
+<dt><code>DisableMovingGc</code></dt>
+<dd>This is not a real GC reason, but a note that collection was blocked due to use of
+GetPrimitiveArrayCritical. while concurrent heap compaction is occuring. In general, the use of
+GetPrimitiveArrayCritical is strongly discouraged due to its restrictions on moving collectors.
+</dd>
+
+<dt><code>HeapTrim</code></dt>
+<dd>This is not a GC reason, but a note that collection was blocked until a heap trim finished.
+</dd>
+
+</dl>
+</dd>
+
+
+<dl>
+<dt>GC Name</dt>
+<dd>
+ART has various different GCs which can get run.
+<dl>
+<dt><code>Concurrent mark sweep (CMS)</code></dt>
+<dd>A whole heap collector which frees collects all spaces other than the image space.</dd>
+
+<dt><code>Concurrent partial mark sweep</code></dt>
+<dd>A mostly whole heap collector which collects all spaces other than the image and zygote spaces.
+</dd>
+
+<dt><code>Concurrent sticky mark sweep</code></dt>
+<dd>A generational collector which can only free objects allocated since the last GC. This garbage
+collection is run more often than a full or partial mark sweep since it is faster and has lower pauses.
+</dd>
+
+<dt><code>Marksweep + semispace</code></dt>
+<dd>A non concurrent, copying GC used for heap transitions as well as homogeneous space
+compaction (to defragement the heap).</dd>
+
+</dl>
+</dd>
+
+<dt>Objects freed</dt>
+<dd>The number of objects which were reclaimed from this GC from the non large
+object space.</dd>
+
+<dt>Size freed</dt>
+<dd>The number of bytes which were reclaimed from this GC from the non large object
+space.</dd>
+
+<dt>Large objects freed</dt>
+<dd>The number of object in the large object space which were reclaimed from this garbage
+collection.</dd>
+
+<dt>Large object size freed</dt>
+<dd>The number of bytes in the large object space which were reclaimed from this garbage
+collection.</dd>
+
+<dt>Heap stats</dt>
+<dd>Percentage free and (number of live objects)/(total heap size).</dd>
+
+<dt>Pause times</dt>
+<dd>In general pause times are proportional to the number of object references which were modified
+while the GC was running. Currently, the ART CMS GCs only has one pause, near the end of the GC.
+The moving GCs have a long pause which lasts for the majority of the GC duration.</dd>
+</dl>
+
+<p>If you are seeing a large amount of GCs in logcat, look for increases in the heap stats (the
+{@code 25MB/38MB} value in the above example). If this value continues to increase and doesn't
+ever seem to get smaller, you could have a memory leak. Alternatively, if you are seeing GC which
+are for the reason "Alloc", then you are already operating near your heap capacity and can expect
+OOM exceptios in the near future. </p>
 
 <h2 id="ViewHeap">Viewing Heap Updates</h2>
 
-<p>To get a little information about what kind of memory your app is using and when, you can view
+<p>To get a little information about what kind of memory your application is using and when, you can view
 real-time updates to your app's heap in the Device Monitor:</p>
 
 <ol>
@@ -117,15 +247,15 @@
 </ol>
 
 <p>The Heap view shows some basic stats about your heap memory usage, updated after every
-garbage collection. To see the first update, click the <strong>Cause GC</strong> button.</p>
+GC. To see the first update, click the <strong>Cause GC</strong> button.</p>
 
 <img src="{@docRoot}images/tools/monitor-vmheap@2x.png" width="760" alt="" />
 <p class="img-caption"><strong>Figure 1.</strong> The Device Monitor tool,
 showing the <strong>[1] Update Heap</strong> and <strong>[2] Cause GC</strong> buttons.
 The Heap tab on the right shows the heap results.</p>
 
-<p>Continue interacting with your app to watch your heap allocation update with each garbage
-collection. This can help you identify which actions in your app are likely causing too much
+<p>Continue interacting with your application to watch your heap allocation update with each garbage
+collection. This can help you identify which actions in your application are likely causing too much
 allocation and where you should try to reduce allocations and release
 resources.</p>
 
@@ -136,9 +266,9 @@
 <p>As you start narrowing down memory issues, you should also use the Allocation Tracker to
 get a better understanding of where your memory-hogging objects are allocated. The Allocation
 Tracker can be useful not only for looking at specific uses of memory, but also to analyze critical
-code paths in an app such as scrolling.</p>
+code paths in an application such as scrolling.</p>
 
-<p>For example, tracking allocations when flinging a list in your app allows you to see all the
+<p>For example, tracking allocations when flinging a list in your application allows you to see all the
 allocations that need to be done for that behavior, what thread they are on, and where they came
 from. This is extremely valuable for tightening up these paths to reduce the work they need and
 improve the overall smoothness of the UI.</p>
@@ -151,7 +281,7 @@
 <li>In the DDMS window, select your app's process in the left-side panel.</li>
 <li>In the right-side panel, select the <strong>Allocation Tracker</strong> tab.</li>
 <li>Click <strong>Start Tracking</strong>.</li>
-<li>Interact with your app to execute the code paths you want to analyze.</li>
+<li>Interact with your application to execute the code paths you want to analyze.</li>
 <li>Click <strong>Get Allocations</strong> every time you want to update the
 list of allocations.</li>
  </ol>
@@ -163,7 +293,7 @@
 
 <img src="{@docRoot}images/tools/monitor-tracker@2x.png" width="760" alt="" />
 <p class="img-caption"><strong>Figure 2.</strong> The Device Monitor tool,
-showing recent app allocations and stack traces in the Allocation Tracker.</p>
+showing recent application allocations and stack traces in the Allocation Tracker.</p>
 
 
 <p class="note"><strong>Note:</strong> You will always see some allocations from {@code
@@ -186,9 +316,11 @@
 following <a href="{@docRoot}tools/help/adb.html">adb</a> command:</p>
 
 <pre class="no-pretty-print">
-adb shell dumpsys meminfo &lt;package_name>
+adb shell dumpsys meminfo &lt;package_name|pid> [-d]
 </pre>
 
+<p>The -d flag prints more info related to Dalvik and ART memory usage.</p>
+
 <p>The output lists all of your app's current allocations, measured in kilobytes.</p>
 
 <p>When inspecting this information, you should be familiar with the
@@ -218,13 +350,57 @@
 total available RAM.</p>
 
 
-<p>For example, below is the the output for Gmail’s process on a tablet device. There is a lot of
+<p>For example, below is the the output for Map’s process on a Nexus 5 device. There is a lot of
 information here, but key points for discussion are listed below.</p>
+<code>adb shell dumpsys meminfo com.google.android.apps.maps -d</code>
 
 <p class="note"><strong>Note:</strong> The information you see may vary slightly from what is shown
 here, as some details of the output differ across platform versions.</p>
 
 <pre class="no-pretty-print">
+** MEMINFO in pid 18227 [com.google.android.apps.maps] **
+                   Pss  Private  Private  Swapped     Heap     Heap     Heap
+                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
+                ------   ------   ------   ------   ------   ------   ------
+  Native Heap    10468    10408        0        0    20480    14462     6017
+  Dalvik Heap    34340    33816        0        0    62436    53883     8553
+ Dalvik Other      972      972        0        0
+        Stack     1144     1144        0        0
+      Gfx dev    35300    35300        0        0
+    Other dev        5        0        4        0
+     .so mmap     1943      504      188        0
+    .apk mmap      598        0      136        0
+    .ttf mmap      134        0       68        0
+    .dex mmap     3908        0     3904        0
+    .oat mmap     1344        0       56        0
+    .art mmap     2037     1784       28        0
+   Other mmap       30        4        0        0
+   EGL mtrack    73072    73072        0        0
+    GL mtrack    51044    51044        0        0
+      Unknown      185      184        0        0
+        TOTAL   216524   208232     4384        0    82916    68345    14570
+
+ Dalvik Details
+        .Heap     6568     6568        0        0
+         .LOS    24771    24404        0        0
+          .GC      500      500        0        0
+    .JITCache      428      428        0        0
+      .Zygote     1093      936        0        0
+   .NonMoving     1908     1908        0        0
+ .IndirectRef       44       44        0        0
+
+ Objects
+               Views:       90         ViewRootImpl:        1
+         AppContexts:        4           Activities:        1
+              Assets:        2        AssetManagers:        2
+       Local Binders:       21        Proxy Binders:       28
+       Parcel memory:       18         Parcel count:       74
+    Death Recipients:        2      OpenSSL Sockets:        2
+</pre>
+
+<p>Here is an older dumpsys on Dalvik of the gmail app:</p>
+
+<pre class="no-pretty-print">
 ** MEMINFO in pid 9953 [com.google.android.gm] **
                  Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap
                Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free
@@ -272,7 +448,7 @@
 
 <p class="note"><strong>Note:</strong> On newer platform versions that have the <code>Dalvik
 Other</code> section, the <code>Pss Total</code> and <code>Private Dirty</code> numbers for Dalvik Heap do
-not include Dalvik overhead such as the just-in-time compilation (JIT) and garbage collection (GC)
+not include Dalvik overhead such as the just-in-time compilation (JIT) and GC
 bookkeeping, whereas older versions list it all combined under <code>Dalvik</code>.</p>
 
 <p>The <code>Heap Alloc</code> is the amount of memory that the Dalvik and native heap allocators keep
@@ -282,12 +458,62 @@
 </dd>
 
 <dt><code>.so mmap</code> and <code>.dex mmap</code></dt>
-<dd>The RAM being used for mmapped <code>.so</code> (native) and <code>.dex</code> (Dalvik) code. The
-<code>Pss Total</code> number includes platform code shared across apps; the <code>Private Clean</code> is
-your app’s own code. Generally, the actual mapped size will be much larger—the RAM here is only
-what currently needs to be in RAM for code that has been executed by the app. However, the .so mmap
-has a large private dirty, which is due to fix-ups to the native code when it was loaded into its
-final address.
+<dd>The RAM being used for mmapped <code>.so</code> (native) and <code>.dex</code> (Dalvik or ART)
+code. The <code>Pss Total</code> number includes platform code shared across apps; the
+<code>Private Clean</code> is your app’s own code. Generally, the actual mapped size will be much
+larger—the RAM here is only what currently needs to be in RAM for code that has been executed by
+the app. However, the .so mmap has a large private dirty, which is due to fix-ups to the native
+code when it was loaded into its final address.
+</dd>
+
+<dt><code>.oat mmap</code></dt>
+<dd>This is the amount of RAM used by the code image which is based off of the preloaded classes
+which are commonly used by multiple apps. This image is shared across all apps and is unaffected
+by particular apps.
+</dd>
+
+<dt><code>.art mmap</code></dt>
+<dd>This is the amount of RAM used by the heap image which is based off of the preloaded classes
+which are commonly used by multiple apps. This image is shared across all apps and is unaffected
+by particular apps. Even though the ART image contains {@link java.lang.Object} instances, it does not
+count towards your heap size.
+</dd>
+
+<dt><code>.Heap</code> (only with -d flag)</dt>
+<dd>This is the amount of heap memory for your app. This excludes objects in the image and large
+object spaces, but includes the zygote space and non-moving space.
+</dd>
+
+<dt><code>.LOS</code> (only with -d flag)</dt>
+<dd>This is the amount of RAM used by the ART large object space. This includes zygote large
+objects. Large objects are all primitive array allocations larger than 12KB.
+</dd>
+
+<dt><code>.GC</code> (only with -d flag)</dt>
+<dd>This is the amount of internal GC accounting overhead for your app. There is not really any way
+to reduce this overhead.
+</dd>
+
+<dt><code>.JITCache</code> (only with -d flag)</dt>
+<dd>This is the amount of memory used by the JIT data and code caches. Typically, this is zero
+since all of the apps will be compiled at installed time.
+</dd>
+
+<dt><code>.Zygote</code> (only with -d flag)</dt>
+<dd>This is the amount of memory used by the zygote space. The zygote space is created during
+device startup and is never allocated into.
+</dd>
+
+<dt><code>.NonMoving</code> (only with -d flag)</dt>
+<dd>This is the amount of RAM used by the ART non-moving space. The non-moving space contains
+special non-movable objects such as fields and methods. You can reduce this section by using fewer
+fields and methods in your app.
+</dd>
+
+<dt><code>.IndirectRef</code> (only with -d flag)</dt>
+<dd>This is the amount of RAM used by the ART indirect reference tables. Usually this amount is
+small, but if it is too high, it may be possible to reduce it by reducing the number of local and
+global JNI references used.
 </dd>
 
 <dt><code>Unknown</code></dt>
@@ -318,7 +544,7 @@
 </dd>
 
 <dt><code>AppContexts</code> and <code>Activities</code></dt>
-<dd>The number of app {@link android.content.Context} and {@link android.app.Activity} objects that
+<dd>The number of application {@link android.content.Context} and {@link android.app.Activity} objects that
 currently live in your process. This can be useful to quickly identify leaked {@link
 android.app.Activity} objects that can’t be garbage collected due to static references on them,
 which is common. These objects often have a lot of other allocations associated with them and so
@@ -327,7 +553,7 @@
 <p class="note"><strong>Note:</strong> A {@link android.view.View} or {@link
 android.graphics.drawable.Drawable} object also holds a reference to the {@link
 android.app.Activity} that it's from, so holding a {@link android.view.View} or {@link
-android.graphics.drawable.Drawable} object can also lead to your app leaking an {@link
+android.graphics.drawable.Drawable} object can also lead to your application leaking an {@link
 android.app.Activity}.</p>
 
 </dd>
@@ -363,13 +589,13 @@
 showing the <strong>[1] Dump HPROF file</strong> button.</p>
 
 <p>If you need to be more precise about when the dump is created, you can also create a heap dump
-at the critical point in your app code by calling {@link android.os.Debug#dumpHprofData
+at the critical point in your application code by calling {@link android.os.Debug#dumpHprofData
 dumpHprofData()}.</p>
 
 <p>The heap dump is provided in a format that's similar to, but not identical to one from the Java
 HPROF tool. The major difference in an Android heap dump is due to the fact that there are a large
 number of allocations in the Zygote process. But because the Zygote allocations are shared across
-all app processes, they don’t matter very much to your own heap analysis.</p>
+all application processes, they don’t matter very much to your own heap analysis.</p>
 
 <p>To analyze your heap dump, you can use a standard tool like jhat or the <a href=
 "http://www.eclipse.org/mat/downloads.php">Eclipse Memory Analyzer Tool</a> (MAT). However, first
@@ -434,7 +660,7 @@
 
   <p class="note"><strong>Note:</strong> Most apps will show an instance of
   {@link android.content.res.Resources} near the top with a good chunk of heap, but this is
-  usually expected when your app uses lots of resources from your {@code res/} directory.</p>
+  usually expected when your application uses lots of resources from your {@code res/} directory.</p>
   </li>
 </ul>
 
@@ -473,19 +699,19 @@
 
 <h2 id="TriggerLeaks">Triggering Memory Leaks</h2>
 
-<p>While using the tools described above, you should aggressively stress your app code and try
-forcing memory leaks. One way to provoke memory leaks in your app is to let it
+<p>While using the tools described above, you should aggressively stress your application code and try
+forcing memory leaks. One way to provoke memory leaks in your application is to let it
 run for a while before inspecting the heap. Leaks will trickle up to the top of the allocations in
-the heap. However, the smaller the leak, the longer you need to run the app in order to see it.</p>
+the heap. However, the smaller the leak, the longer you need to run the application in order to see it.</p>
 
 <p>You can also trigger a memory leak in one of the following ways:</p>
 <ol>
 <li>Rotate the device from portrait to landscape and back again multiple times while in different
-activity states. Rotating the device can often cause an app to leak an {@link android.app.Activity},
+activity states. Rotating the device can often cause an application to leak an {@link android.app.Activity},
 {@link android.content.Context}, or {@link android.view.View} object because the system
-recreates the {@link android.app.Activity} and if your app holds a reference
+recreates the {@link android.app.Activity} and if your application holds a reference
 to one of those objects somewhere else, the system can't garbage collect it.</li>
-<li>Switch between your app and another app while in different activity states (navigate to
+<li>Switch between your application and another application while in different activity states (navigate to
 the Home screen, then return to your app).</li>
 </ol>
 
diff --git a/docs/html/tools/extras/oem-usb.jd b/docs/html/tools/extras/oem-usb.jd
index b25b41e..6d449ee 100644
--- a/docs/html/tools/extras/oem-usb.jd
+++ b/docs/html/tools/extras/oem-usb.jd
@@ -32,12 +32,13 @@
 To start developing with your device, read <a
 href="{@docRoot}tools/device.html">Using Hardware Devices</a>.</p>
 
-<p class="note"><strong>Note:</strong> If your device is one of the Android Developer Phones
-(ADP), a Nexus One, or a Nexus S, then you need
-the <a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a>, instead of an OEM driver. The Galaxy
-Nexus driver, however, is distributed by <a
-href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a>
-(listed as model SCH-I515).</p>
+<p>The Google USB Driver is <strong>required for Windows only</strong> in order to perform
+<a href="{@docRoot}tools/help/adb.html">adb</a> debugging with any of
+the <strong>Google Nexus devices</strong>. The one exception is the
+Galaxy Nexus: the driver for Galaxy Nexus is distributed by <a
+href="http://www.samsung.com/us/support/owners/product/GT-I9250TSGGEN">Samsung</a>
+(listed as model GT-I9250TSGGEN).</p>
+
 
 
 <h2 id="InstallingDriver">Installing a USB Driver</h2>
@@ -99,7 +100,7 @@
   <li>Select <strong>Device Manager</strong> in the left pane of the Computer Management
   window.</li>
   <li>Locate and expand <em>Android Phone</em> in the right pane.</li>
-  <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update
+  <li>Right-click on <em>Android Composite ADB Interface</em> and select <strong>Update
   Driver</strong>.
     This will launch the Hardware Update Wizard.</li>
   <li>Select <strong>Install from a list or specific location</strong> and click
@@ -145,14 +146,14 @@
     and select <strong>Manage</strong>.</li>
   <li>Select <strong>Device Manager</strong> in the left pane.</li>
   <li>Locate and expand <em>ADB Interface</em> in the right pane.</li>
-  <li>Right-click on <em>HTC Dream Composite ADB Interface</em>, and select <strong>Update
+  <li>Right-click on <em>Android Composite ADB Interface</em>, and select <strong>Update
   Driver Software</strong>.</li>
   <li>When Vista starts updating the driver, a prompt will ask how you want to
   search for the driver
     software. Select <strong>Browse my computer for driver software</strong>.</li>
   <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB
 Driver is located in {@code &lt;sdk&gt;\extras\google\usb_driver\}.) As long as you specified the
-exact location of the 
+exact location of the
     installation package, you may leave <strong>Include subfolders</strong> checked or
     unchecked&mdash;it doesn't matter.</li>
   <li>Click <strong>Next</strong>. Vista might prompt you to confirm the privilege elevation
@@ -164,13 +165,6 @@
 
 <h2 id="Drivers">OEM Drivers</h2>
 
-<p class="note"><strong>Note:</strong> If your device is one of the Android Developer Phones
-(purchased from the Google Play Developer Console), a Nexus One, or a Nexus S, then you need
-the <a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a>, instead of an OEM driver. The Galaxy
-Nexus driver, however, is distributed by <a
-href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a>
-(listed as model SCH-I515).</p>
-
 
 <table><tr>
     <th>OEM</th>
diff --git a/docs/html/tools/help/adb.jd b/docs/html/tools/help/adb.jd
index e2dd196..41c6686 100644
--- a/docs/html/tools/help/adb.jd
+++ b/docs/html/tools/help/adb.jd
@@ -962,7 +962,6 @@
 </code></td>
 <td>Installs a package (specified by {@code &lt;PATH>}) to the system.  <p>Options:
   <ul>
-    <li>{@code -l}: Install the package with forward lock.
     <li>{@code -r}: Reinstall an exisiting app, keeping its data.
     <li>{@code -t}: Allow test APKs to be installed.
     <li>{@code -i &lt;INSTALLER_PACKAGE_NAME>}: Specify the installer package name.
diff --git a/docs/html/tools/help/systrace.jd b/docs/html/tools/help/systrace.jd
index d6fc05e..4461da9 100644
--- a/docs/html/tools/help/systrace.jd
+++ b/docs/html/tools/help/systrace.jd
@@ -68,7 +68,8 @@
   <ol>
     <li>In <a href="{@docRoot}sdk/installing/studio.html">Android Studio</a>, open an
       Android application project.</li>
-    <li>Open the Device Monitor by selecting <strong>Tools &gt; Android &gt; Monitor</strong>.</li>
+    <li>Open the Device Monitor by selecting <strong>Tools &gt; Android &gt; Android Device
+      Monitor</strong>.</li>
     <li>In the <strong>Devices</strong> tab, select the device on which to run a trace. If no
       devices are listed, make sure your device is connected via USB cable and that debugging is
       enabled on the device.</li>
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index e297d26..5e5cf37 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -52,6 +52,11 @@
  */
 public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
 
+    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
+    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
     private final Context mContext;
 
     private final String mKeystoreAlias;
@@ -147,22 +152,29 @@
             throw new IllegalArgumentException("context == null");
         } else if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
-        } else if (subjectDN == null) {
-            throw new IllegalArgumentException("subjectDN == null");
-        } else if (serialNumber == null) {
-            throw new IllegalArgumentException("serialNumber == null");
-        } else if (startDate == null) {
-            throw new IllegalArgumentException("startDate == null");
-        } else if (endDate == null) {
-            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");
         }
 
+        if (subjectDN == null) {
+            subjectDN = DEFAULT_CERT_SUBJECT;
+        }
+        if (startDate == null) {
+            startDate = DEFAULT_CERT_NOT_BEFORE;
+        }
+        if (endDate == null) {
+            endDate = DEFAULT_CERT_NOT_AFTER;
+        }
+        if (serialNumber == null) {
+            serialNumber = DEFAULT_CERT_SERIAL_NUMBER;
+        }
+
+        if (endDate.before(startDate)) {
+            throw new IllegalArgumentException("endDate < startDate");
+        }
+
         mContext = context;
         mKeystoreAlias = keyStoreAlias;
         mKeyType = keyType;
@@ -556,6 +568,10 @@
         /**
          * Sets the subject used for the self-signed certificate of the
          * generated key pair.
+         *
+         * <p>The subject must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the subject defaults to {@code CN=fake} if not specified.
          */
         public Builder setSubject(X500Principal subject) {
             if (subject == null) {
@@ -568,6 +584,10 @@
         /**
          * Sets the serial number used for the self-signed certificate of the
          * generated key pair.
+         *
+         * <p>The serial number must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the serial number defaults to {@code 1} if not specified.
          */
         public Builder setSerialNumber(BigInteger serialNumber) {
             if (serialNumber == null) {
@@ -580,6 +600,10 @@
         /**
          * Sets the start of the validity period for the self-signed certificate
          * of the generated key pair.
+         *
+         * <p>The date must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the date defaults to {@code Jan 1 1970} if not specified.
          */
         public Builder setStartDate(Date startDate) {
             if (startDate == null) {
@@ -592,6 +616,10 @@
         /**
          * Sets the end of the validity period for the self-signed certificate
          * of the generated key pair.
+         *
+         * <p>The date must be specified on API Level
+         * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+         * newer platforms the date defaults to {@code Jan 1 2048} if not specified.
          */
         public Builder setEndDate(Date endDate) {
             if (endDate == null) {
diff --git a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
index bc8dd13..681a9ff 100644
--- a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
@@ -24,6 +24,11 @@
 import javax.security.auth.x500.X500Principal;
 
 public class KeyPairGeneratorSpecTest extends AndroidTestCase {
+    private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+    private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+    private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1980
+    private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
     private static final String TEST_ALIAS_1 = "test1";
 
     private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
@@ -105,46 +110,37 @@
         }
     }
 
-    public void testConstructor_NullSubjectDN_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when subjectDN is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullSubjectDN_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
+                NOW_PLUS_10_YEARS, 0);
+        assertEquals(DEFAULT_CERT_SUBJECT, spec.getSubjectDN());
     }
 
-    public void testConstructor_NullSerial_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when startDate is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullSerial_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
+                NOW_PLUS_10_YEARS, 0);
+        assertEquals(DEFAULT_CERT_SERIAL_NUMBER, spec.getSerialNumber());
     }
 
-    public void testConstructor_NullStartDate_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    null, NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when startDate is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullStartDate_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, null,
+                NOW_PLUS_10_YEARS, 0);
+        assertEquals(DEFAULT_CERT_NOT_BEFORE, spec.getStartDate());
     }
 
-    public void testConstructor_NullEndDate_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    NOW, null, 0);
-            fail("Should throw IllegalArgumentException when keystoreAlias is null");
-        } catch (IllegalArgumentException success) {
-        }
+    public void testConstructor_NullEndDate_Success() throws Exception {
+        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+                getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, null, 0);
+        assertEquals(DEFAULT_CERT_NOT_AFTER, spec.getEndDate());
     }
 
     public void testConstructor_EndBeforeStart_Failure() throws Exception {
         try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    NOW_PLUS_10_YEARS, NOW, 0);
+            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1,
+                    SERIAL_1, NOW_PLUS_10_YEARS, NOW, 0);
             fail("Should throw IllegalArgumentException when end is before start");
         } catch (IllegalArgumentException success) {
         }
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 71088b7..8b11757 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -709,7 +709,7 @@
 
 void SkiaCanvas::drawTextOnPath(const uint16_t* glyphs, int count, const SkPath& path,
         float hOffset, float vOffset, const SkPaint& paint) {
-    mCanvas->drawTextOnPathHV(glyphs, count, path, hOffset, vOffset, paint);
+    mCanvas->drawTextOnPathHV(glyphs, count << 1, path, hOffset, vOffset, paint);
 }
 
 } // namespace android
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
index bc5a8a1..480a18c 100644
--- a/location/lib/java/com/android/location/provider/FusedLocationHardware.java
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
@@ -34,7 +34,7 @@
  * Class that exposes IFusedLocationHardware functionality to unbundled services.
  */
 public final class FusedLocationHardware {
-    private final String TAG = "FusedLocationHardware";
+    private static final String TAG = "FusedLocationHardware";
 
     private IFusedLocationHardware mLocationHardware;
 
@@ -52,6 +52,16 @@
         public void onDiagnosticDataAvailable(String data) {
             dispatchDiagnosticData(data);
         }
+
+        @Override
+        public void onCapabilities(int capabilities) {
+            dispatchCapabilities(capabilities);
+        }
+
+        @Override
+        public void onStatusChanged(int status) {
+            dispatchStatus(status);
+        }
     };
 
     /**
@@ -164,6 +174,14 @@
         }
     }
 
+    public void flushBatchedLocations() {
+        try {
+            mLocationHardware.flushBatchedLocations();
+        } catch(RemoteException e) {
+            Log.e(TAG, "RemoteException at flushBatchedLocations");
+        }
+    }
+
     public boolean supportsDiagnosticDataInjection() {
         try {
             return mLocationHardware.supportsDiagnosticDataInjection();
@@ -204,6 +222,8 @@
     private class DispatcherHandler extends Handler {
         public static final int DISPATCH_LOCATION = 1;
         public static final int DISPATCH_DIAGNOSTIC_DATA = 2;
+        public static final int DISPATCH_CAPABILITIES = 3;
+        public static final int DISPATCH_STATUS = 4;
 
         public DispatcherHandler(Looper looper) {
             super(looper, null /*callback*/ , true /*async*/);
@@ -218,6 +238,13 @@
                     break;
                 case DISPATCH_DIAGNOSTIC_DATA:
                     command.dispatchDiagnosticData();
+                    break;
+                case DISPATCH_CAPABILITIES:
+                    command.dispatchCapabilities();
+                    break;
+                case DISPATCH_STATUS:
+                    command.dispatchStatus();
+                    break;
                 default:
                     Log.e(TAG, "Invalid dispatch message");
                     break;
@@ -229,14 +256,20 @@
         private final FusedLocationHardwareSink mSink;
         private final Location[] mLocations;
         private final String mData;
+        private final int mCapabilities;
+        private final int mStatus;
 
         public MessageCommand(
                 FusedLocationHardwareSink sink,
                 Location[] locations,
-                String data) {
+                String data,
+                int capabilities,
+                int status) {
             mSink = sink;
             mLocations = locations;
             mData = data;
+            mCapabilities = capabilities;
+            mStatus = status;
         }
 
         public void dispatchLocation() {
@@ -246,6 +279,14 @@
         public void dispatchDiagnosticData() {
             mSink.onDiagnosticDataAvailable(mData);
         }
+
+        public void dispatchCapabilities() {
+            mSink.onCapabilities(mCapabilities);
+        }
+
+        public void dispatchStatus() {
+            mSink.onStatusChanged(mStatus);
+        }
     }
 
     private void dispatchLocations(Location[] locations) {
@@ -258,7 +299,7 @@
             Message message = Message.obtain(
                     entry.getValue(),
                     DispatcherHandler.DISPATCH_LOCATION,
-                    new MessageCommand(entry.getKey(), locations, null /*data*/));
+                    new MessageCommand(entry.getKey(), locations, null /*data*/, 0, 0));
             message.sendToTarget();
         }
     }
@@ -273,7 +314,37 @@
             Message message = Message.obtain(
                     entry.getValue(),
                     DispatcherHandler.DISPATCH_DIAGNOSTIC_DATA,
-                    new MessageCommand(entry.getKey(), null /*locations*/, data));
+                    new MessageCommand(entry.getKey(), null /*locations*/, data, 0, 0));
+            message.sendToTarget();
+        }
+    }
+
+    private void dispatchCapabilities(int capabilities) {
+        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
+        synchronized(mSinkList) {
+            sinks = mSinkList;
+        }
+
+        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
+            Message message = Message.obtain(
+                    entry.getValue(),
+                    DispatcherHandler.DISPATCH_CAPABILITIES,
+                    new MessageCommand(entry.getKey(), null /*locations*/, null, capabilities, 0));
+            message.sendToTarget();
+        }
+    }
+
+    private void dispatchStatus(int status) {
+        HashMap<FusedLocationHardwareSink, DispatcherHandler> sinks;
+        synchronized(mSinkList) {
+            sinks = mSinkList;
+        }
+
+        for(Map.Entry<FusedLocationHardwareSink, DispatcherHandler> entry : sinks.entrySet()) {
+            Message message = Message.obtain(
+                    entry.getValue(),
+                    DispatcherHandler.DISPATCH_STATUS,
+                    new MessageCommand(entry.getKey(), null /*locations*/, null, 0, status));
             message.sendToTarget();
         }
     }
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
index 2c39fa8..618d5d6 100644
--- a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
@@ -20,11 +20,47 @@
 
 /**
  * Base class for sinks to interact with FusedLocationHardware.
+ *
+ * <p>Default implementations allow new methods to be added without crashing
+ * clients compiled against an old library version.
  */
-public abstract class FusedLocationHardwareSink {
-    /*
-     * Methods to provide a facade for IFusedLocationHardware
+public class FusedLocationHardwareSink {
+    /**
+     * Called when one or more locations are available from the FLP
+     * HAL.
      */
-    public abstract void onLocationAvailable(Location[] locations);
-    public abstract void onDiagnosticDataAvailable(String data);
+    public void onLocationAvailable(Location[] locations) {
+        // default do nothing
+    }
+
+    /**
+     * Called when diagnostic data is available from the FLP HAL.
+     */
+    public void onDiagnosticDataAvailable(String data) {
+        // default do nothing
+    }
+
+    /**
+     * Called when capabilities are available from the FLP HAL.
+     * Should be called once right after initialization.
+     *
+     * @param capabilities A bitmask of capabilities defined in
+     *                     fused_location.h.
+     */
+    public void onCapabilities(int capabilities) {
+        // default do nothing
+    }
+
+    /**
+     * Called when the status changes in the underlying FLP HAL
+     * implementation (the ability to compute location).  This
+     * callback will only be made on API 23 or later.
+     *
+     * @param status One of FLP_STATUS_LOCATION_AVAILABLE or
+     *               FLP_STATUS_LOCATION_UNAVAILABLE as defined in
+     *               fused_location.h.
+     */
+    public void onStatusChanged(int status) {
+        // default do nothing
+    }
 }
\ No newline at end of file
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 9c6d640..fac69ea 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -214,6 +214,8 @@
     private final Object mPlayStateLock = new Object();
     /**
      * Sizes of the native audio buffer.
+     * These values are set during construction and can be stale.
+     * To obtain the current native audio buffer frame count use {@link #getNativeFrameCount()}.
      */
     private int mNativeBufferSizeInBytes = 0;
     private int mNativeBufferSizeInFrames = 0;
@@ -312,15 +314,20 @@
      *   {@link AudioFormat#ENCODING_PCM_8BIT},
      *   and {@link AudioFormat#ENCODING_PCM_FLOAT}.
      * @param bufferSizeInBytes the total size (in bytes) of the internal buffer where audio data is
-     *   read from for playback.
-     *   If track's creation mode is {@link #MODE_STREAM}, you can write data into
-     *   this buffer in chunks less than or equal to this size, and it is typical to use
-     *   chunks of 1/2 of the total size to permit double-buffering.
-     *   If the track's creation mode is {@link #MODE_STATIC},
+     *   read from for playback. This should be a multiple of the frame size in bytes.
+     *   <p> If the track's creation mode is {@link #MODE_STATIC},
      *   this is the maximum length sample, or audio clip, that can be played by this instance.
-     *   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 getMinBufferSize() will result in an initialization failure.
+     *   <p> If the track's creation mode is {@link #MODE_STREAM},
+     *   this should be the desired buffer size
+     *   for the <code>AudioTrack</code> to satisfy the application's
+     *   natural latency requirements.
+     *   If <code>bufferSizeInBytes</code> is less than the
+     *   minimum buffer size for the output sink, it is automatically increased to the minimum
+     *   buffer size.
+     *   The method {@link #getNativeFrameCount()} returns the
+     *   actual size in frames of the native buffer created, which
+     *   determines the frequency to write
+     *   to the streaming <code>AudioTrack</code> to avoid underrun.
      * @param mode streaming or static buffer. See {@link #MODE_STATIC} and {@link #MODE_STREAM}
      * @throws java.lang.IllegalArgumentException
      */
@@ -512,8 +519,10 @@
      * {@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 buffer size is not specified with {@link #setBufferSizeInBytes(int)},
+     * and the mode is {@link AudioTrack#MODE_STREAM}, the minimum buffer size is used.
      * <br>If the transfer mode is not specified with {@link #setTransferMode(int)},
-     * {@link AudioTrack#MODE_STREAM} will be used.
+     * <code>MODE_STREAM</code> will be used.
      * <br>If the session ID is not specified with {@link #setSessionId(int)}, a new one will
      * be generated.
      */
@@ -648,6 +657,13 @@
                         .build();
             }
             try {
+                // If the buffer size is not specified in streaming mode,
+                // use a single frame for the buffer size and let the
+                // native code figure out the minimum buffer size.
+                if (mMode == MODE_STREAM && mBufferSizeInBytes == 0) {
+                    mBufferSizeInBytes = mFormat.getChannelCount()
+                            * mFormat.getBytesPerSample(mFormat.getEncoding());
+                }
                 return new AudioTrack(mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId);
             } catch (IllegalArgumentException e) {
                 throw new UnsupportedOperationException(e.getMessage());
@@ -986,19 +1002,22 @@
     }
 
     /**
-     *  Returns the "native frame count", derived from the bufferSizeInBytes specified at
-     *  creation time and converted to frame units.
-     *  If track's creation mode is {@link #MODE_STATIC},
-     *  it is equal to the specified bufferSizeInBytes converted to frame units.
-     *  If track's creation mode is {@link #MODE_STREAM},
-     *  it is typically greater than or equal to the specified bufferSizeInBytes converted to frame
-     *  units; it may be rounded up to a larger value if needed by the target device implementation.
-     *  @deprecated Only accessible by subclasses, which are not recommended for AudioTrack.
-     *  See {@link AudioManager#getProperty(String)} for key
+     *  Returns the "native frame count" of the <code>AudioTrack</code> buffer.
+     *  <p> If the track's creation mode is {@link #MODE_STATIC},
+     *  it is equal to the specified bufferSizeInBytes on construction, converted to frame units.
+     *  A static track's native frame count will not change.
+     *  <p> If the track's creation mode is {@link #MODE_STREAM},
+     *  it is greater than or equal to the specified bufferSizeInBytes converted to frame units.
+     *  For streaming tracks, this value may be rounded up to a larger value if needed by
+     *  the target output sink, and
+     *  if the track is subsequently routed to a different output sink, the native
+     *  frame count may enlarge to accommodate.
+     *  See also {@link AudioManager#getProperty(String)} for key
      *  {@link AudioManager#PROPERTY_OUTPUT_FRAMES_PER_BUFFER}.
+     *  @return current size in frames of the audio track buffer.
+     *  @throws IllegalStateException
      */
-    @Deprecated
-    protected int getNativeFrameCount() {
+    public int getNativeFrameCount() throws IllegalStateException {
         return native_get_native_frame_count();
     }
 
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index ebf73da..ce06e65 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -124,6 +124,8 @@
     private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768);
     private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
     private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
+    private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
+    private static final int MAX_SUPPORTED_INSTANCES_LIMIT = 256;
 
     // found stuff that is not supported by framework (=> this should not happen)
     private static final int ERROR_UNRECOGNIZED   = (1 << 0);
@@ -147,6 +149,7 @@
 
         // CLASSIFICATION
         private String mMime;
+        private int mMaxSupportedInstances;
 
         // LEGACY FIELDS
 
@@ -366,6 +369,18 @@
             return mMime;
         }
 
+        /**
+         * Returns the max number of the supported concurrent codec instances.
+         * <p>
+         * This is a hint for an upper bound. Applications should not expect to successfully
+         * operate more instances than the returned value, but the actual number of
+         * concurrently operable instances may be less as it depends on the available
+         * resources at time of use.
+         */
+        public int getMaxSupportedInstances() {
+            return mMaxSupportedInstances;
+        }
+
         private boolean isAudio() {
             return mAudioCaps != null;
         }
@@ -467,6 +482,15 @@
                 mEncoderCaps.setDefaultFormat(mDefaultFormat);
             }
 
+            final Map<String, Object> global = MediaCodecList.getGlobalSettings();
+            mMaxSupportedInstances = Utils.parseIntSafely(
+                    global.get("max-supported-instances"), DEFAULT_MAX_SUPPORTED_INSTANCES);
+
+            int maxInstances = Utils.parseIntSafely(
+                    map.get("max-supported-instances"), mMaxSupportedInstances);
+            mMaxSupportedInstances =
+                    Range.create(1, MAX_SUPPORTED_INSTANCES_LIMIT).clamp(maxInstances);
+
             for (Feature feat: getValidFeatures()) {
                 String key = MediaFormat.KEY_FEATURE_ + feat.mName;
                 Integer yesNo = (Integer)map.get(key);
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 7fd0186..f44e048 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -21,6 +21,7 @@
 import android.media.MediaCodecInfo;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Map;
 
 /**
  * Allows you to enumerate available codecs, each specified as a {@link MediaCodecInfo} object,
@@ -61,13 +62,19 @@
         return sRegularCodecInfos[index];
     }
 
+    /* package private */ static final Map<String, Object> getGlobalSettings() {
+        return sGlobalSettings;
+    }
+
     private static Object sInitLock = new Object();
     private static MediaCodecInfo[] sAllCodecInfos;
     private static MediaCodecInfo[] sRegularCodecInfos;
+    private static Map<String, Object> sGlobalSettings;
 
     private static final void initCodecList() {
         synchronized (sInitLock) {
             if (sRegularCodecInfos == null) {
+                sGlobalSettings = native_getGlobalSettings();
                 int count = native_getCodecCount();
                 ArrayList<MediaCodecInfo> regulars = new ArrayList<MediaCodecInfo>();
                 ArrayList<MediaCodecInfo> all = new ArrayList<MediaCodecInfo>();
@@ -112,6 +119,8 @@
     /* package private */ static native final MediaCodecInfo.CodecCapabilities
         getCodecCapabilities(int index, String type);
 
+    /* package private */ static native final Map<String, Object> native_getGlobalSettings();
+
     /* package private */ static native final int findCodecByName(String codec);
 
     /** @hide */
diff --git a/media/java/android/media/VolumePolicy.java b/media/java/android/media/VolumePolicy.java
index 2d3376a..1d33128 100644
--- a/media/java/android/media/VolumePolicy.java
+++ b/media/java/android/media/VolumePolicy.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.Objects;
+
 /** @hide */
 public final class VolumePolicy implements Parcelable {
     public static final VolumePolicy DEFAULT = new VolumePolicy(false, false, true, 400);
@@ -53,6 +55,23 @@
     }
 
     @Override
+    public int hashCode() {
+        return Objects.hash(volumeDownToEnterSilent, volumeUpToExitSilent, doNotDisturbWhenSilent,
+                vibrateToSilentDebounce);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof VolumePolicy)) return false;
+        if (o == this) return true;
+        final VolumePolicy other = (VolumePolicy) o;
+        return other.volumeDownToEnterSilent == volumeDownToEnterSilent
+                && other.volumeUpToExitSilent == volumeUpToExitSilent
+                && other.doNotDisturbWhenSilent == doNotDisturbWhenSilent
+                && other.vibrateToSilentDebounce == vibrateToSilentDebounce;
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index f8c349b..82dd48d 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -262,6 +262,27 @@
     return caps;
 }
 
+static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobject /* thiz */) {
+    sp<IMediaCodecList> mcl = getCodecList(env);
+    if (mcl == NULL) {
+        // Runtime exception already pending.
+        return NULL;
+    }
+
+    const sp<AMessage> settings = mcl->getGlobalSettings();
+    if (settings == NULL) {
+        jniThrowException(env, "java/lang/RuntimeException", "cannot get global settings");
+        return NULL;
+    }
+
+    jobject settingsObj = NULL;
+    if (ConvertMessageToMap(env, settings, &settingsObj)) {
+        return NULL;
+    }
+
+    return settingsObj;
+}
+
 static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
 }
 
@@ -277,6 +298,10 @@
       "(ILjava/lang/String;)Landroid/media/MediaCodecInfo$CodecCapabilities;",
       (void *)android_media_MediaCodecList_getCodecCapabilities },
 
+    { "native_getGlobalSettings",
+      "()Ljava/util/Map;",
+      (void *)android_media_MediaCodecList_getGlobalSettings },
+
     { "findCodecByName", "(Ljava/lang/String;)I",
       (void *)android_media_MediaCodecList_findCodecByName },
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index e05e1fc..0466540 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -160,7 +160,7 @@
         assertEquals(CameraBinderTestUtils.NO_ERROR, status);
         assertFalse(metadata.isEmpty());
 
-        CaptureRequest.Builder request = new CaptureRequest.Builder(metadata);
+        CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false);
         assertFalse(request.isEmpty());
         assertFalse(metadata.isEmpty());
         if (needStream) {
diff --git a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
index 7e09a5b..9b55e5b 100644
--- a/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/Keyguard/res/layout/keyguard_emergency_carrier_area.xml
@@ -46,7 +46,7 @@
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:layout_marginTop="@dimen/eca_overlap"
-        android:text="@string/kg_emergency_call_label"
+        android:text="@*android:string/lockscreen_emergency_call"
         style="?android:attr/buttonBarButtonStyle"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textSize="@dimen/kg_status_line_font_size"
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index df221fa..e060b4a 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -122,8 +122,6 @@
     <!-- Description of the Enter button in a KeyboardView. [CHAR LIMIT=NONE] -->
     <string name="keyboardview_keycode_enter">Enter</string>
 
-    <!-- Label shown on emergency call button in keyguard -->
-    <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 -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 0b6ab99..870f043 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -2066,7 +2066,7 @@
                     LockPatternUtils lpu = new LockPatternUtils(mContext);
                     List<LockPatternView.Cell> cellPattern =
                             LockPatternUtils.stringToPattern(lockPattern);
-                    lpu.saveLockPattern(cellPattern);
+                    lpu.saveLockPattern(cellPattern, null);
                 } catch (IllegalArgumentException e) {
                     // Don't want corrupted lock pattern to hang the reboot process
                 }
diff --git a/packages/SystemUI/res/drawable/ic_delete.xml b/packages/SystemUI/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..4e80ddf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_delete.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M12 38c0 2.21 1.79 4 4 4h16c2.21 0 4,-1.79 4,-4V14H12v24zM38 8h-7l-2,-2H19l-2 2h-7v4h28V8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_person.xml b/packages/SystemUI/res/drawable/ic_person.xml
new file mode 100644
index 0000000..101911f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_person.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT 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="48.0"
+        android:viewportHeight="48.0">
+    <path
+        android:fillColor="#ffffffff"
+        android:pathData="M24 24c4.42 0 8,-3.59 8,-8 0,-4.42,-3.58,-8,-8,-8s-8 3.58,-8 8c0 4.41 3.58 8 8 8zm0 4c-5.33 0,-16 2.67,-16 8v4h32v-4c0,-5.33,-10.67,-8,-16,-8z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
new file mode 100644
index 0000000..3c4c646
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.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="23.0dp"
+        android:height="18.0dp"
+        android:viewportWidth="21.0"
+        android:viewportHeight="17.0">
+    <group android:translateX="2.0">
+        <path
+            android:fillColor="#FF000000"
+            android:pathData="M9.9,11.6H7v-1.1H2.1v2.8c0,0.8,0.6,1.4,1.4,1.4h9.9c0.8,0,1.4,-0.6,1.4,-1.4v-2.8H9.9V11.6z"/>
+        <path
+            android:fillColor="#FF000000"
+            android:pathData="M14.1,4.2h-2.5V3.2l-1.1,-1.1H6.3L5.3,3.2v1H2.8C2,4.2,1.4,4.9,1.4,5.6v2.8c0,0.8,0.6,1.4,1.4,1.4H7V8.8h2.8v1.1h4.2     c0.8,0,1.4,-0.6,1.4,-1.4V5.6C15.5,4.9,14.8,4.2,14.1,4.2z M10.6,4.2H6.3V3.2h4.2V4.2z"/>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 7586227..c86e9dc 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -41,8 +41,6 @@
         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! :-) -->
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index af27cc4..b51aa96 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -16,6 +16,8 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:paddingStart="4dp"
+    android:paddingEnd="4dp"
     android:clipChildren="false" >
 
     <TextView
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
index c491e9c..dcdc859 100644
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ b/packages/SystemUI/res/layout/volume_zen_footer.xml
@@ -24,6 +24,8 @@
         android:id="@+id/volume_zen_switch_bar"
         android:layout_width="match_parent"
         android:layout_height="@dimen/volume_button_size"
+        android:layout_marginStart="4dp"
+        android:layout_marginEnd="4dp"
         android:clickable="true"
         android:orientation="horizontal" >
 
@@ -49,6 +51,7 @@
             android:layout_width="wrap_content"
             android:layout_height="fill_parent"
             android:layout_marginEnd="11dp" />
+
     </LinearLayout>
 
     <RelativeLayout
@@ -56,8 +59,8 @@
         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" >
+        android:paddingEnd="7dp"
+        android:paddingStart="7dp" >
 
         <TextView
             android:id="@+id/volume_zen_panel_summary_line_1"
@@ -79,6 +82,8 @@
         android:id="@+id/volume_zen_mode_panel_buttons"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginStart="4dp"
+        android:layout_marginEnd="4dp"
         android:gravity="end" >
 
         <TextView
diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml
index 3d73ff7..d829f0e 100644
--- a/packages/SystemUI/res/layout/zen_mode_panel.xml
+++ b/packages/SystemUI/res/layout/zen_mode_panel.xml
@@ -19,7 +19,6 @@
     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" >
 
@@ -28,6 +27,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:minHeight="8dp"
+        android:layout_marginStart="39dp"
         android:elevation="4dp"
         android:background="@drawable/qs_background_secondary" >
 
@@ -46,15 +46,13 @@
         android:layout_width="match_parent"
         android:layout_height="1dp"
         android:visibility="gone"
-        android:layout_marginStart="@dimen/qs_panel_padding"
-        android:layout_marginEnd="@dimen/qs_panel_padding"
-        android:layout_marginBottom="@dimen/qs_panel_padding"
         android:background="#4dffffff" />
 
     <RelativeLayout
         android:id="@+id/zen_subhead"
         android:layout_width="match_parent"
         android:layout_height="62dp"
+        android:layout_marginStart="39dp"
         android:gravity="center_vertical"
         android:paddingLeft="8dp"
         android:paddingRight="8dp" >
@@ -98,10 +96,60 @@
 
     </RelativeLayout>
 
+    <RelativeLayout
+        android:id="@+id/zen_introduction"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingEnd="4dp"
+        android:paddingTop="8dp"
+        android:paddingBottom="8dp"
+        android:background="@color/zen_introduction_message_background" >
+
+        <ImageView
+            android:id="@+id/zen_introduction_confirm"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:layout_alignParentEnd="true"
+            android:background="@drawable/btn_borderless_rect"
+            android:clickable="true"
+            android:contentDescription="@string/accessibility_desc_confirm"
+            android:scaleType="center"
+            android:src="@drawable/ic_close"
+            android:tint="@android:color/white" />
+
+        <TextView
+            android:id="@+id/zen_introduction_message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dp"
+            android:layout_marginStart="55dp"
+            android:lineSpacingMultiplier="1.20029"
+            android:layout_toStartOf="@id/zen_introduction_confirm"
+            android:text="@string/zen_priority_introduction"
+            android:textAppearance="@style/TextAppearance.QS.VolumeSuppressor" />
+
+        <TextView
+            android:id="@+id/zen_introduction_customize"
+            style="@style/QSBorderlessButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentEnd="true"
+            android:layout_marginEnd="4dp"
+            android:layout_below="@id/zen_introduction_message"
+            android:clickable="true"
+            android:focusable="true"
+            android:text="@string/zen_priority_customize_button"
+            android:textAppearance="@style/TextAppearance.QS.DetailButton.White" />
+
+    </RelativeLayout>
+
     <LinearLayout
         android:id="@+id/zen_conditions"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:layout_marginTop="8dp"
+        android:layout_marginEnd="4dp"
+        android:layout_marginStart="39dp"
         android:orientation="vertical"
         android:paddingBottom="@dimen/zen_mode_condition_detail_bottom_padding" />
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index ded7c4e..88d1769 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -44,6 +44,7 @@
     <color name="qs_subhead">#99FFFFFF</color><!-- 60% white -->
     <color name="qs_detail_empty">#24B0BEC5</color><!-- 14% blue grey 200 -->
     <color name="qs_detail_button">#FFB0BEC5</color><!-- 100% blue grey 200 -->
+    <color name="qs_detail_button_white">#B3FFFFFF</color><!-- 70% white -->
     <color name="qs_detail_transition">#66FFFFFF</color>
     <color name="qs_detail_progress_track">#99009688</color><!-- 60% deep teal 500 -->
     <color name="data_usage_secondary">#99FFFFFF</color><!-- 60% white -->
@@ -137,4 +138,6 @@
     <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>
+
+    <color name="zen_introduction_message_background">#ff009688</color><!-- deep teal 500 -->
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 779b55e..ae134c6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -410,6 +410,8 @@
     <string name="accessibility_desc_settings">Settings</string>
     <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_recent_apps">Overview.</string>
+    <!-- Content description for the confirm button in the zen mode panel introduction message. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_confirm">Confirm</string>
 
     <!-- Content description of the user tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_user">User <xliff:g id="user" example="John Doe">%s</xliff:g>.</string>
@@ -723,6 +725,12 @@
     <!-- Zen mode: No interruptions title, with a warning about alarms. [CHAR LIMIT=60] -->
     <string name="zen_no_interruptions_with_warning">No interruptions. Not even alarms.</string>
 
+    <!-- Zen mode: Priority only introduction message on first use -->
+    <string name="zen_priority_introduction">You won\'t be disturbed by sounds and vibrations, except from alarms, reminders, events, and callers you specify.</string>
+
+    <!-- Zen mode: Priority only customization button label -->
+    <string name="zen_priority_customize_button">Customize</string>
+
     <!-- Zen mode: No interruptions. [CHAR LIMIT=40] -->
     <string name="zen_no_interruptions">No interruptions</string>
 
@@ -830,6 +838,15 @@
     <!-- Notification when resuming an existing guest session: Action that continues with the current session [CHAR LIMIT=35] -->
     <string name="guest_wipe_session_dontwipe">Yes, continue</string>
 
+    <!-- Title of the notification shown to a new guest user [CHAR LIMIT=60] -->
+    <string name="guest_notification_title">Guest user</string>
+
+    <!-- Text of the notification shown to a new guest user [CHAR LIMIT=60] -->
+    <string name="guest_notification_text">Remove guest to delete apps and data</string>
+
+    <!-- Remove action in the notification shown to a new guest user [CHAR LIMIT=30] -->
+    <string name="guest_notification_remove_action">REMOVE GUEST</string>
+
     <!-- Title for add user confirmation dialog [CHAR LIMIT=30] -->
     <string name="user_add_user_title" msgid="2108112641783146007">Add new user?</string>
 
@@ -982,4 +999,7 @@
 
     <!-- Volume dialog zen toggle switch title -->
     <string name="volume_zen_switch_text">@*android:string/zen_mode_feature_name</string>
+
+    <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
+    <string name="managed_profile_foreground_toast">You are in the Work profile</string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 107a8ec..974cc48 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -151,6 +151,10 @@
         <item name="android:gravity">center</item>
     </style>
 
+    <style name="TextAppearance.QS.DetailButton.White">
+        <item name="android:textColor">@color/qs_detail_button_white</item>
+    </style>
+
     <style name="TextAppearance.QS.DetailEmpty">
         <item name="android:textSize">@dimen/qs_detail_empty_text_size</item>
         <item name="android:textColor">@color/qs_subhead</item>
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 9df67fd..68b1968 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -35,7 +35,10 @@
         Key.HOTSPOT_TILE_LAST_USED,
         Key.COLOR_INVERSION_TILE_LAST_USED,
         Key.DND_TILE_VISIBLE,
-        Key.DND_TILE_COMBINED_ICON
+        Key.DND_TILE_COMBINED_ICON,
+        Key.DND_CONFIRMED_PRIORITY_INTRODUCTION,
+        Key.DND_FAVORITE_BUCKET_INDEX,
+        Key.DND_NONE_SELECTED,
     })
     public @interface Key {
         String SEARCH_APP_WIDGET_ID = "searchAppWidgetId";
@@ -44,6 +47,9 @@
         String COLOR_INVERSION_TILE_LAST_USED = "ColorInversionTileLastUsed";
         String DND_TILE_VISIBLE = "DndTileVisible";
         String DND_TILE_COMBINED_ICON = "DndTileCombinedIcon";
+        String DND_CONFIRMED_PRIORITY_INTRODUCTION = "DndConfirmedPriorityIntroduction";
+        String DND_FAVORITE_BUCKET_INDEX = "DndCountdownMinuteIndex";
+        String DND_NONE_SELECTED = "DndNoneSelected";
     }
 
     public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index d2837b7..ee607a7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -80,6 +80,7 @@
 import android.widget.ImageView;
 import android.widget.RemoteViews;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -378,6 +379,23 @@
                 userSwitched(mCurrentUserId);
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 updateCurrentProfilesCache();
+            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
+                List<ActivityManager.RecentTaskInfo> recentTask = null;
+                try {
+                    recentTask = ActivityManagerNative.getDefault().getRecentTasks(1,
+                            ActivityManager.RECENT_WITH_EXCLUDED
+                            | ActivityManager.RECENT_INCLUDE_PROFILES,
+                            mCurrentUserId);
+                } catch (RemoteException e) {
+                    // Abandon hope activity manager not running.
+                }
+                if (recentTask != null && recentTask.size() > 0) {
+                    UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
+                    if (user != null && user.isManagedProfile()) {
+                        Toast.makeText(mContext, R.string.managed_profile_foreground_toast,
+                                Toast.LENGTH_SHORT).show();
+                    }
+                }
             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
                     action)) {
                 mUsersAllowingPrivateNotifications.clear();
@@ -612,6 +630,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
+        filter.addAction(Intent.ACTION_USER_PRESENT);
         filter.addAction(BANNER_ACTION_CANCEL);
         filter.addAction(BANNER_ACTION_SETUP);
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
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 7c199cd..b0d6178 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3288,8 +3288,10 @@
         }
         if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
             mScrimController.setKeyguardShowing(true);
+            mIconPolicy.setKeyguardShowing(true);
         } else {
             mScrimController.setKeyguardShowing(false);
+            mIconPolicy.setKeyguardShowing(false);
         }
         mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
         updateDozingState();
@@ -3724,6 +3726,9 @@
         if (!mKeyguardFadingAway) {
             mIconController.appTransitionStarting(startTime, duration);
         }
+        if (mIconPolicy != null) {
+            mIconPolicy.appTransitionStarting(startTime, duration);
+        }
     }
 
     private final class ShadeUpdates {
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 ac93ced..fb42ba1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -16,16 +16,22 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
+import android.app.IUserSwitchObserver;
 import android.app.StatusBarManager;
 import android.bluetooth.BluetoothAdapter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings.Global;
 import android.telecom.TelecomManager;
 import android.util.Log;
@@ -54,6 +60,7 @@
     private static final String SLOT_ZEN = "zen";
     private static final String SLOT_VOLUME = "volume";
     private static final String SLOT_ALARM_CLOCK = "alarm_clock";
+    private static final String SLOT_MANAGED_PROFILE = "managed_profile";
 
     private final Context mContext;
     private final StatusBarManager mService;
@@ -72,6 +79,10 @@
 
     private boolean mBluetoothEnabled = false;
 
+    private boolean mManagedProfileFocused = false;
+    private boolean mManagedProfileIconVisible = true;
+
+    private boolean mKeyguardVisible = true;
 
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -94,9 +105,6 @@
             else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) {
                 updateTTY(intent);
             }
-            else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
-                updateAlarm();
-            }
         }
     };
 
@@ -115,9 +123,15 @@
         filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
         filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
 
+        // listen for user / profile change.
+        try {
+            ActivityManagerNative.getDefault().registerUserSwitchObserver(mUserSwitchListener);
+        } catch (RemoteException e) {
+            // Ignore
+        }
+
         // TTY status
         mService.setIcon(SLOT_TTY,  R.drawable.stat_sys_tty_mode, 0, null);
         mService.setIconVisibility(SLOT_TTY, false);
@@ -147,6 +161,10 @@
         mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null);
         mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled());
         mHotspot.addCallback(mHotspotCallback);
+
+        // managed profile
+        mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0, null);
+        mService.setIconVisibility(SLOT_MANAGED_PROFILE, false);
     }
 
     public void setZenMode(int zen) {
@@ -298,6 +316,53 @@
         mService.setIconVisibility(SLOT_CAST, isCasting);
     }
 
+    private void profileChanged(int userId) {
+        UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        UserInfo user = null;
+        if (userId == UserHandle.USER_CURRENT) {
+            try {
+                user = ActivityManagerNative.getDefault().getCurrentUser();
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        } else {
+            user = userManager.getUserInfo(userId);
+        }
+
+        mManagedProfileFocused = user != null && user.isManagedProfile();
+        if (DEBUG) Log.v(TAG, "profileChanged: mManagedProfileFocused: " + mManagedProfileFocused);
+        // Actually update the icon later when transition starts.
+    }
+
+    private void updateManagedProfile() {
+        if (DEBUG) Log.v(TAG, "updateManagedProfile: mManagedProfileFocused: "
+                + mManagedProfileFocused
+                + " mKeyguardVisible: " + mKeyguardVisible);
+        boolean showIcon = mManagedProfileFocused && !mKeyguardVisible;
+        if (mManagedProfileIconVisible != showIcon) {
+            mService.setIconVisibility(SLOT_MANAGED_PROFILE, showIcon);
+            mManagedProfileIconVisible = showIcon;
+        }
+    }
+
+    private final IUserSwitchObserver.Stub mUserSwitchListener =
+            new IUserSwitchObserver.Stub() {
+                @Override
+                public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+                }
+
+                @Override
+                public void onUserSwitchComplete(int newUserId) throws RemoteException {
+                    updateAlarm();
+                    profileChanged(newUserId);
+                }
+
+                @Override
+                public void onForegroundProfileSwitch(int newProfileId) {
+                    profileChanged(newProfileId);
+                }
+            };
+
     private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() {
         @Override
         public void onHotspotChanged(boolean enabled) {
@@ -311,4 +376,13 @@
             updateCast();
         }
     };
+
+    public void appTransitionStarting(long startTime, long duration) {
+        updateManagedProfile();
+    }
+
+    public void setKeyguardShowing(boolean visible) {
+        mKeyguardVisible = visible;
+        updateManagedProfile();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 4ac41a1..194bcfa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -19,6 +19,9 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.Dialog;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
@@ -63,6 +66,7 @@
     private static final boolean DEBUG = false;
     private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING =
             "lockscreenSimpleUserSwitcher";
+    private static final String ACTION_REMOVE_GUEST = "com.android.systemui.REMOVE_GUEST";
 
     private final Context mContext;
     private final UserManager mUserManager;
@@ -89,6 +93,7 @@
         filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_STOPPING);
+        filter.addAction(ACTION_REMOVE_GUEST);
         mContext.registerReceiverAsUser(mReceiver, UserHandle.OWNER, filter,
                 null /* permission */, null /* scheduler */);
 
@@ -296,6 +301,22 @@
                 Log.v(TAG, "Broadcast: a=" + intent.getAction()
                        + " user=" + intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
             }
+            if (ACTION_REMOVE_GUEST.equals(intent.getAction())) {
+                int currentUser = ActivityManager.getCurrentUser();
+                UserInfo userInfo = mUserManager.getUserInfo(currentUser);
+                if (userInfo != null && userInfo.isGuest()) {
+                    showExitGuestDialog(currentUser);
+                }
+                return;
+            }
+            if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
+                final int currentId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                UserInfo userInfo = mUserManager.getUserInfo(currentId);
+                if (userInfo != null && userInfo.isGuest()) {
+                    showGuestNotification(currentId);
+                }
+            }
+
             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
                 if (mExitGuestDialog != null && mExitGuestDialog.isShowing()) {
                     mExitGuestDialog.cancel();
@@ -329,6 +350,24 @@
             }
             refreshUsers(forcePictureLoadForId);
         }
+
+        private void showGuestNotification(int guestUserId) {
+            PendingIntent removeGuestPI = PendingIntent.getBroadcastAsUser(mContext,
+                    0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.OWNER);
+            Notification notification = new Notification.Builder(mContext)
+                    .setVisibility(Notification.VISIBILITY_SECRET)
+                    .setPriority(Notification.PRIORITY_MIN)
+                    .setSmallIcon(R.drawable.ic_person)
+                    .setContentTitle(mContext.getString(R.string.guest_notification_title))
+                    .setContentText(mContext.getString(R.string.guest_notification_text))
+                    .setShowWhen(false)
+                    .addAction(R.drawable.ic_delete,
+                            mContext.getString(R.string.guest_notification_remove_action),
+                            removeGuestPI)
+                    .build();
+            NotificationManager.from(mContext).notifyAsUser(null, 0, notification,
+                    new UserHandle(guestUserId));
+        }
     };
 
     private final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
index 9928f7f..23a65e8 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -93,7 +93,8 @@
     }
 
     @Override
-    protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
+    protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) {
+        final ResolveInfo ri = target.getResolveInfo();
         try {
             IBinder b = ServiceManager.getService(USB_SERVICE);
             IUsbManager service = IUsbManager.Stub.asInterface(b);
@@ -121,7 +122,7 @@
             }
 
             try {
-                startActivityAsUser(intent, new UserHandle(userId));
+                target.startAsUser(this, null, new UserHandle(userId));
             } catch (ActivityNotFoundException e) {
                 Log.e(TAG, "startActivity failed", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 539fec8..bb4aa61 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -107,20 +107,22 @@
     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 boolean mShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
+    private boolean mShowFooter = VolumePrefs.DEFAULT_SHOW_FOOTER;
+    private boolean mShowZenFooter = VolumePrefs.DEFAULT_ZEN_FOOTER;
+    private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
+    private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
     private State mState;
     private int mExpandButtonRes;
     private boolean mExpanding;
     private SafetyWarningDialog mSafetyWarning;
+    private Callback mCallback;
 
     public VolumeDialog(Context context, VolumeDialogController controller,
-            ZenModeController zenModeController) {
+            ZenModeController zenModeController, Callback callback) {
         mContext = context;
         mController = controller;
+        mCallback = callback;
         mSpTexts = new SpTexts(mContext);
         mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
 
@@ -421,14 +423,6 @@
         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);
@@ -885,7 +879,9 @@
                 @Override
                 public void run() {
                     Events.writeEvent(Events.EVENT_SETTINGS_CLICK);
-                    onSettingsClickedH();
+                    if (mCallback != null) {
+                        mCallback.onSettingsClicked();
+                    }
                 }
             }, WAIT_FOR_RIPPLE);
         }
@@ -912,13 +908,23 @@
         @Override
         public void onSettingsClicked() {
             dismiss(Events.DISMISS_REASON_SETTINGS_CLICKED);
-            onZenSettingsClickedH();
+            if (mCallback != null) {
+                mCallback.onZenSettingsClicked();
+            }
         }
 
         @Override
         public void onDoneClicked() {
             dismiss(Events.DISMISS_REASON_DONE_CLICKED);
         }
+
+        @Override
+        public void onPrioritySettingsClicked() {
+            dismiss(Events.DISMISS_REASON_SETTINGS_CLICKED);
+            if (mCallback != null) {
+                mCallback.onZenPrioritySettingsClicked();
+            }
+        }
     };
 
     private final class H extends Handler {
@@ -1052,10 +1058,16 @@
         private boolean important;
         private int cachedIconRes;
         private int iconState;  // from Events
-        private boolean cachedShowHeaders = Prefs.DEFAULT_SHOW_HEADERS;
+        private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
         private int cachedExpandButtonRes;
         private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
         private int animTargetProgress;
         private int lastAudibleLevel = 1;
     }
+
+    public interface Callback {
+        void onSettingsClicked();
+        void onZenSettingsClicked();
+        void onZenPrioritySettingsClicked();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 741e498..86abfcc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -17,11 +17,13 @@
 package com.android.systemui.volume;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.media.VolumePolicy;
 import android.os.Bundle;
 import android.os.Handler;
+import android.provider.Settings;
 
 import com.android.systemui.SystemUI;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -41,6 +43,12 @@
     private final VolumeDialogController mController;
     private final ZenModeController mZenModeController;
     private final VolumeDialog mDialog;
+    private final VolumePolicy mVolumePolicy = new VolumePolicy(
+            true,  // volumeDownToEnterSilent
+            true,  // volumeUpToExitSilent
+            true,  // doNotDisturbWhenSilent
+            400    // vibrateToSilentDebounce
+    );
 
     public VolumeDialogComponent(SystemUI sysui, Context context, Handler handler,
             ZenModeController zen) {
@@ -53,12 +61,7 @@
             }
         };
         mZenModeController = zen;
-        mDialog = new VolumeDialog(context, mController, zen) {
-            @Override
-            protected void onZenSettingsClickedH() {
-                startZenSettings();
-            }
-        };
+        mDialog = new VolumeDialog(context, mController, zen, mVolumeDialogCallback);
         applyConfiguration();
     }
 
@@ -77,7 +80,7 @@
         mDialog.setZenFooter(true);
         mDialog.setAutomute(true);
         mDialog.setSilentMode(false);
-        mController.setVolumePolicy(VolumePolicy.DEFAULT);
+        mController.setVolumePolicy(mVolumePolicy);
         mController.showDndTile(false);
     }
 
@@ -113,8 +116,26 @@
         mDialog.dump(pw);
     }
 
-    private void startZenSettings() {
-        mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(
-                ZenModePanel.ZEN_SETTINGS, true /* onlyProvisioned */, true /* dismissShade */);
+    private void startSettings(Intent intent) {
+        mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(intent,
+                true /* onlyProvisioned */, true /* dismissShade */);
     }
+
+    private final VolumeDialog.Callback mVolumeDialogCallback = new VolumeDialog.Callback() {
+        @Override
+        public void onSettingsClicked() {
+            startSettings(new Intent(Settings.ACTION_NOTIFICATION_SETTINGS));
+        }
+
+        @Override
+        public void onZenSettingsClicked() {
+            startSettings(ZenModePanel.ZEN_SETTINGS);
+        }
+
+        @Override
+        public void onZenPrioritySettingsClicked() {
+            startSettings(ZenModePanel.ZEN_PRIORITY_SETTINGS);
+        }
+    };
+
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 5bc8c3e..012eb41 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -99,7 +99,7 @@
 
     private boolean mEnabled;
     private boolean mDestroyed;
-    private VolumePolicy mVolumePolicy = new VolumePolicy(true, true, false, 400);
+    private VolumePolicy mVolumePolicy;
     private boolean mShowDndTile = false;
 
     public VolumeDialogController(Context context, ComponentName component) {
@@ -147,6 +147,7 @@
 
     public void setVolumePolicy(VolumePolicy policy) {
         mVolumePolicy = policy;
+        if (mVolumePolicy == null) return;
         try {
             mAudio.setVolumePolicy(mVolumePolicy);
         } catch (NoSuchMethodError e) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index f16e9d2..45cb4a1 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -428,6 +428,13 @@
             }
 
             @Override
+            public void onPrioritySettings() {
+                if (mCallback != null) {
+                    mCallback.onZenPrioritySettings();
+                }
+            }
+
+            @Override
             public void onInteraction() {
                 resetTimeout();
             }
@@ -1524,6 +1531,7 @@
 
     public interface Callback {
         void onZenSettings();
+        void onZenPrioritySettings();
         void onInteraction();
         void onVisible(boolean visible);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java
index fa6ea9e..b072cab 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanelComponent.java
@@ -17,6 +17,7 @@
 package com.android.systemui.volume;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.media.IRemoteVolumeController;
@@ -74,6 +75,12 @@
             }
 
             @Override
+            public void onZenPrioritySettings() {
+                mHandler.removeCallbacks(mStartZenPrioritySettings);
+                mHandler.post(mStartZenPrioritySettings);
+            }
+
+            @Override
             public void onInteraction() {
                 final KeyguardViewMediator kvm = mSysui.getComponent(KeyguardViewMediator.class);
                 if (kvm != null) {
@@ -126,12 +133,23 @@
         mPanel.postDismiss(0);
     }
 
+    private void startSettings(Intent intent) {
+        mSysui.getComponent(PhoneStatusBar.class).startActivityDismissingKeyguard(intent,
+                true /* onlyProvisioned */, true /* dismissShade */);
+        mPanel.postDismiss(mDismissDelay);
+    }
+
     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);
+            startSettings(ZenModePanel.ZEN_SETTINGS);
+        }
+    };
+
+    private final Runnable mStartZenPrioritySettings = new Runnable() {
+        @Override
+        public void run() {
+            startSettings(ZenModePanel.ZEN_PRIORITY_SETTINGS);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Prefs.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/volume/Prefs.java
rename to packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
index 58bc9f4..915e998 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePrefs.java
@@ -24,7 +24,7 @@
 /**
  *  Configuration for the volume dialog + related policy.
  */
-public class Prefs {
+public class VolumePrefs {
 
     public static final String PREF_ENABLE_PROTOTYPE = "pref_enable_prototype";  // not persistent
     public static final String PREF_SHOW_ALARMS = "pref_show_alarms";
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index 387aed0..e979786 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -36,6 +36,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.qs.tiles.DndTile;
@@ -172,18 +173,40 @@
         private static final String DISABLE = "com.android.systemui.vui.DISABLE";
         private static final String EXTRA_COMPONENT = "component";
 
+        private static final String PREF = "com.android.systemui.PREF";
+        private static final String EXTRA_KEY = "key";
+        private static final String EXTRA_VALUE = "value";
+
         public void start() {
             final IntentFilter filter = new IntentFilter();
             filter.addAction(ENABLE);
             filter.addAction(DISABLE);
+            filter.addAction(PREF);
             mContext.registerReceiver(this, filter, null, mHandler);
         }
 
         @Override
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
+            if (PREF.equals(action)) {
+                final String key = intent.getStringExtra(EXTRA_KEY);
+                if (key != null && intent.getExtras() != null) {
+                    final Object value = intent.getExtras().get(EXTRA_VALUE);
+                    if (value == null) {
+                        Prefs.remove(mContext, key);
+                    } else if (value instanceof Boolean) {
+                        Prefs.putBoolean(mContext, key, (Boolean) value);
+                    } else if (value instanceof Integer) {
+                        Prefs.putInt(mContext, key, (Integer) value);
+                    } else if (value instanceof Long) {
+                        Prefs.putLong(mContext, key, (Long) value);
+                    }
+                }
+                return;
+            }
             final ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT);
-            final boolean current = component.equals(mVolumeControllerService.getComponent());
+            final boolean current = component != null
+                    && component.equals(mVolumeControllerService.getComponent());
             if (ENABLE.equals(action) && component != null) {
                 if (!current) {
                     showServiceActivationDialog(component);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index ef8257c..775c87d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -99,6 +99,7 @@
         mController = controller;
         mZenModePanel.init(controller);
         mZenModePanel.setEmbedded(true);
+        mZenModePanel.setCallback(mZenModePanelCallback);
         mSwitch.setOnCheckedChangeListener(mCheckedListener);
         mController.addCallback(new ZenModeController.Callback() {
             @Override
@@ -212,13 +213,38 @@
         Util.setText(mSummaryLine2, line2);
     }
 
+    private final ZenModePanel.Callback mZenModePanelCallback = new ZenModePanel.Callback() {
+        @Override
+        public void onMoreSettings() {
+            if (mCallback != null) {
+                mCallback.onSettingsClicked();
+            }
+        }
+
+        @Override
+        public void onPrioritySettings() {
+            if (mCallback != null) {
+                mCallback.onPrioritySettingsClicked();
+            }
+        }
+
+        @Override
+        public void onInteraction() {
+            // noop
+        }
+
+        @Override
+        public void onExpanded(boolean expanded) {
+            // noop
+        }
+    };
+
     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;
+                final int newZen = isChecked ? Global.ZEN_MODE_ALARMS : Global.ZEN_MODE_OFF;
                 mZen = newZen;  // this one's optimistic
                 setFooterExpanded(isChecked);
                 mController.setZen(newZen, null, TAG);
@@ -230,5 +256,6 @@
         void onFooterExpanded();
         void onSettingsClicked();
         void onDoneClicked();
+        void onPrioritySettingsClicked();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index f6d4c36..1b563dc 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -50,6 +50,7 @@
 import android.widget.RadioButton;
 import android.widget.TextView;
 
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.ZenModeController;
 
@@ -74,12 +75,15 @@
     private static final int FOREVER_CONDITION_INDEX = 0;
     private static final int COUNTDOWN_CONDITION_INDEX = 1;
 
-    public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+    public static final Intent ZEN_SETTINGS
+            = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+    public static final Intent ZEN_PRIORITY_SETTINGS
+            = new Intent(Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS);
 
     private final Context mContext;
     private final LayoutInflater mInflater;
     private final H mHandler = new H();
-    private final Prefs mPrefs;
+    private final ZenPrefs mPrefs;
     private final IconPulser mIconPulser;
     private final int mSubheadWarningColor;
     private final int mSubheadColor;
@@ -96,6 +100,9 @@
     private TextView mZenSubheadExpanded;
     private View mZenEmbeddedDivider;
     private View mMoreSettings;
+    private View mZenIntroduction;
+    private View mZenIntroductionConfirm;
+    private View mZenIntroductionCustomize;
     private LinearLayout mZenConditions;
 
     private Callback mCallback;
@@ -121,7 +128,7 @@
     public ZenModePanel(Context context, AttributeSet attrs) {
         super(context, attrs);
         mContext = context;
-        mPrefs = new Prefs();
+        mPrefs = new ZenPrefs();
         mInflater = LayoutInflater.from(mContext.getApplicationContext());
         mIconPulser = new IconPulser(mContext);
         mSubheadWarningColor = context.getColor(R.color.system_warning_color);
@@ -202,11 +209,36 @@
         });
         Interaction.register(mMoreSettings, mInteractionCallback);
 
+        mZenIntroduction = findViewById(R.id.zen_introduction);
+        mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
+        mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                confirmZenIntroduction();
+            }
+        });
+        mZenIntroductionCustomize = findViewById(R.id.zen_introduction_customize);
+        mZenIntroductionCustomize.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                confirmZenIntroduction();
+                if (mCallback != null) {
+                    mCallback.onPrioritySettings();
+                }
+            }
+        });
+
         mZenConditions = (LinearLayout) findViewById(R.id.zen_conditions);
 
         setLayoutTransition(newLayoutTransition(mTransitionHelper));
     }
 
+    private void confirmZenIntroduction() {
+        if (DEBUG) Log.d(TAG, "confirmZenIntroduction");
+        Prefs.putBoolean(mContext, Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, true);
+        mHandler.sendEmptyMessage(H.UPDATE_WIDGETS);
+    }
+
     private LayoutTransition newLayoutTransition(TransitionListener listener) {
         final LayoutTransition transition = new LayoutTransition();
         transition.disableTransitionType(LayoutTransition.DISAPPEARING);
@@ -452,13 +484,15 @@
         final boolean zenImportant = zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
         final boolean expanded = !mHidden && mExpanded;
+        final boolean conditions = mEmbedded || !zenOff && expanded;
+        final boolean introduction = conditions && zenImportant && !mPrefs.mConfirmedIntroduction;
 
         mZenButtons.setVisibility(mHidden ? GONE : VISIBLE);
         mZenSubhead.setVisibility(!mHidden && !zenOff && !mEmbedded ? VISIBLE : GONE);
         mZenSubheadExpanded.setVisibility(expanded ? VISIBLE : GONE);
         mZenSubheadCollapsed.setVisibility(!expanded ? VISIBLE : GONE);
         mMoreSettings.setVisibility(zenImportant && expanded ? VISIBLE : GONE);
-        mZenConditions.setVisibility(mEmbedded || !zenOff && expanded ? VISIBLE : GONE);
+        mZenConditions.setVisibility(conditions ? VISIBLE : GONE);
 
         if (zenNone) {
             mZenSubheadExpanded.setText(R.string.zen_no_interruptions_with_warning);
@@ -469,6 +503,7 @@
         }
         mZenSubheadExpanded.setTextColor(zenNone && mPrefs.isNoneDangerous()
                 ? mSubheadWarningColor : mSubheadColor);
+        mZenIntroduction.setVisibility(introduction ? VISIBLE : GONE);
     }
 
     private static Condition parseExistingTimeCondition(Context context, Condition condition) {
@@ -835,6 +870,7 @@
     private final class H extends Handler {
         private static final int UPDATE_CONDITIONS = 1;
         private static final int MANUAL_RULE_CHANGED = 2;
+        private static final int UPDATE_WIDGETS = 3;
 
         private H() {
             super(Looper.getMainLooper());
@@ -842,16 +878,17 @@
 
         @Override
         public void handleMessage(Message msg) {
-            if (msg.what == UPDATE_CONDITIONS) {
-                handleUpdateConditions((Condition[]) msg.obj);
-            } else if (msg.what == MANUAL_RULE_CHANGED) {
-                handleUpdateManualRule((ZenRule) msg.obj);
+            switch (msg.what) {
+                case UPDATE_CONDITIONS: handleUpdateConditions((Condition[]) msg.obj); break;
+                case MANUAL_RULE_CHANGED: handleUpdateManualRule((ZenRule) msg.obj); break;
+                case UPDATE_WIDGETS: updateWidgets(); break;
             }
         }
     }
 
     public interface Callback {
         void onMoreSettings();
+        void onPrioritySettings();
         void onInteraction();
         void onExpanded(boolean expanded);
     }
@@ -865,21 +902,20 @@
         Condition condition;
     }
 
-    private final class Prefs implements OnSharedPreferenceChangeListener {
-        private static final String KEY_MINUTE_INDEX = "minuteIndex";
-        private static final String KEY_NONE_SELECTED = "noneSelected";
-
+    private final class ZenPrefs implements OnSharedPreferenceChangeListener {
         private final int mNoneDangerousThreshold;
 
         private int mMinuteIndex;
         private int mNoneSelected;
+        private boolean mConfirmedIntroduction;
 
-        private Prefs() {
+        private ZenPrefs() {
             mNoneDangerousThreshold = mContext.getResources()
                     .getInteger(R.integer.zen_mode_alarm_warning_threshold);
-            prefs().registerOnSharedPreferenceChangeListener(this);
+            Prefs.registerListener(mContext, this);
             updateMinuteIndex();
             updateNoneSelected();
+            updateConfirmedIntroduction();
         }
 
         public boolean isNoneDangerous() {
@@ -890,7 +926,7 @@
             mNoneSelected = clampNoneSelected(mNoneSelected + 1);
             if (DEBUG) Log.d(mTag, "Setting none selected: " + mNoneSelected + " threshold="
                     + mNoneDangerousThreshold);
-            prefs().edit().putInt(KEY_NONE_SELECTED, mNoneSelected).apply();
+            Prefs.putInt(mContext, Prefs.Key.DND_NONE_SELECTED, mNoneSelected);
         }
 
         public int getMinuteIndex() {
@@ -902,21 +938,19 @@
             if (minuteIndex == mMinuteIndex) return;
             mMinuteIndex = clampIndex(minuteIndex);
             if (DEBUG) Log.d(mTag, "Setting favorite minute index: " + mMinuteIndex);
-            prefs().edit().putInt(KEY_MINUTE_INDEX, mMinuteIndex).apply();
+            Prefs.putInt(mContext, Prefs.Key.DND_FAVORITE_BUCKET_INDEX, mMinuteIndex);
         }
 
         @Override
         public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
             updateMinuteIndex();
             updateNoneSelected();
-        }
-
-        private SharedPreferences prefs() {
-            return mContext.getSharedPreferences(mContext.getPackageName(), 0);
+            updateConfirmedIntroduction();
         }
 
         private void updateMinuteIndex() {
-            mMinuteIndex = clampIndex(prefs().getInt(KEY_MINUTE_INDEX, DEFAULT_BUCKET_INDEX));
+            mMinuteIndex = clampIndex(Prefs.getInt(mContext,
+                    Prefs.Key.DND_FAVORITE_BUCKET_INDEX, DEFAULT_BUCKET_INDEX));
             if (DEBUG) Log.d(mTag, "Favorite minute index: " + mMinuteIndex);
         }
 
@@ -925,13 +959,22 @@
         }
 
         private void updateNoneSelected() {
-            mNoneSelected = clampNoneSelected(prefs().getInt(KEY_NONE_SELECTED, 0));
+            mNoneSelected = clampNoneSelected(Prefs.getInt(mContext,
+                    Prefs.Key.DND_NONE_SELECTED, 0));
             if (DEBUG) Log.d(mTag, "None selected: " + mNoneSelected);
         }
 
         private int clampNoneSelected(int noneSelected) {
             return MathUtils.constrain(noneSelected, 0, Integer.MAX_VALUE);
         }
+
+        private void updateConfirmedIntroduction() {
+            final boolean confirmed =  Prefs.getBoolean(mContext,
+                    Prefs.Key.DND_CONFIRMED_PRIORITY_INTRODUCTION, false);
+            if (confirmed == mConfirmedIntroduction) return;
+            mConfirmedIntroduction = confirmed;
+            if (DEBUG) Log.d(mTag, "Confirmed introduction: " + mConfirmedIntroduction);
+        }
     }
 
     private final SegmentedButtons.Callback mZenButtonsCallback = new SegmentedButtons.Callback() {
diff --git a/preloaded-classes b/preloaded-classes
index 151766f..86bd5c9 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1791,7 +1791,6 @@
 com.android.internal.telephony.ITelephonyRegistry$Stub
 com.android.internal.telephony.ITelephonyRegistry$Stub$Proxy
 com.android.internal.telephony.PhoneConstants$State
-com.android.internal.transition.ActionBarTransition
 com.android.internal.util.ArrayUtils
 com.android.internal.util.FastPrintWriter
 com.android.internal.util.FastPrintWriter$1
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 5fc1f93..7c927fd 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -332,10 +332,12 @@
       rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
     }
 
-    native long rsnScriptGroup2Create(long con, String cachePath, long[] closures);
-    synchronized long nScriptGroup2Create(String cachePath, long[] closures) {
+    native long rsnScriptGroup2Create(long con, String name, String cachePath,
+                                      long[] closures);
+    synchronized long nScriptGroup2Create(String name, String cachePath,
+                                          long[] closures) {
       validate();
-      return rsnScriptGroup2Create(mContext, cachePath, closures);
+      return rsnScriptGroup2Create(mContext, name, cachePath, closures);
     }
 
     native void rsnScriptGroup2Execute(long con, long groupID);
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
index 858a957..96bb6e2 100644
--- a/rs/java/android/renderscript/ScriptGroup2.java
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -323,6 +323,7 @@
         }
     }
 
+    String mName;
     List<Closure> mClosures;
     List<UnboundValue> mInputs;
     Future[] mOutputs;
@@ -333,9 +334,10 @@
         super(id, rs);
     }
 
-    ScriptGroup2(RenderScript rs, List<Closure> closures,
+    ScriptGroup2(RenderScript rs, String name, List<Closure> closures,
                  List<UnboundValue> inputs, Future[] outputs) {
         super(0, rs);
+        mName = name;
         mClosures = closures;
         mInputs = inputs;
         mOutputs = outputs;
@@ -344,7 +346,7 @@
         for (int i = 0; i < closureIDs.length; i++) {
             closureIDs[i] = closures.get(i).getID(rs);
         }
-        long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs);
+        long id = rs.nScriptGroup2Create(name, ScriptC.mCachePath, closureIDs);
         setID(id);
     }
 
@@ -560,7 +562,7 @@
                 !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
                 throw new RSIllegalArgumentException("invalid script group name");
             }
-            ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
+            ScriptGroup2 ret = new ScriptGroup2(mRS, name, mClosures, mInputs, outputs);
             return ret;
         }
 
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 783df68..49afa6d 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -418,8 +418,9 @@
 }
 
 static long
-nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con,
+nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, jstring name,
                     jstring cacheDir, jlongArray closureArray) {
+  AutoJavaStringToUTF8 nameUTF(_env, name);
   AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
 
   jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
@@ -430,7 +431,8 @@
   }
 
   return (jlong)(uintptr_t)rsScriptGroup2Create(
-      (RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length(),
+      (RsContext)con, nameUTF.c_str(), nameUTF.length(),
+      cacheDirUTF.c_str(), cacheDirUTF.length(),
       closures, numClosures);
 }
 
@@ -2404,7 +2406,7 @@
 {"rsnScriptInvokeIDCreate",          "(JJI)J",                                (void*)nScriptInvokeIDCreate },
 {"rsnScriptFieldIDCreate",           "(JJI)J",                                (void*)nScriptFieldIDCreate },
 {"rsnScriptGroupCreate",             "(J[J[J[J[J[J)J",                        (void*)nScriptGroupCreate },
-{"rsnScriptGroup2Create",            "(JLjava/lang/String;[J)J",               (void*)nScriptGroup2Create },
+{"rsnScriptGroup2Create",            "(JLjava/lang/String;Ljava/lang/String;[J)J", (void*)nScriptGroup2Create },
 {"rsnScriptGroupSetInput",           "(JJJJ)V",                               (void*)nScriptGroupSetInput },
 {"rsnScriptGroupSetOutput",          "(JJJJ)V",                               (void*)nScriptGroupSetOutput },
 {"rsnScriptGroupExecute",            "(JJ)V",                                 (void*)nScriptGroupExecute },
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 34e8b78..9f80fd8 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -99,6 +99,7 @@
     static final boolean DEBUG_BATCH = localLOGV || false;
     static final boolean DEBUG_VALIDATE = localLOGV || false;
     static final boolean DEBUG_ALARM_CLOCK = localLOGV || false;
+    static final boolean RECORD_ALARMS_IN_HISTORY = true;
     static final int ALARM_EVENT = 1;
     static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
@@ -1345,15 +1346,6 @@
     }
 
     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;
@@ -1574,13 +1566,6 @@
     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
@@ -1816,6 +1801,17 @@
                 if (localLOGV) {
                     Slog.v(TAG, "sending alarm " + alarm);
                 }
+                if (RECORD_ALARMS_IN_HISTORY) {
+                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
+                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
+                            ActivityManagerNative.noteAlarmStart(
+                                    alarm.operation, alarm.workSource.get(wi), alarm.tag);
+                        }
+                    } else {
+                        ActivityManagerNative.noteAlarmStart(
+                                alarm.operation, -1, alarm.tag);
+                    }
+                }
                 alarm.operation.send(getContext(), 0,
                         mBackgroundIntent.putExtra(
                                 Intent.EXTRA_ALARM_COUNT, alarm.count),
@@ -1856,11 +1852,11 @@
                         for (int wi=0; wi<alarm.workSource.size(); wi++) {
                             ActivityManagerNative.noteWakeupAlarm(
                                     alarm.operation, alarm.workSource.get(wi),
-                                    alarm.workSource.getName(wi));
+                                    alarm.workSource.getName(wi), alarm.tag);
                         }
                     } else {
                         ActivityManagerNative.noteWakeupAlarm(
-                                alarm.operation, -1, null);
+                                alarm.operation, -1, null, alarm.tag);
                     }
                 }
             } catch (PendingIntent.CanceledException e) {
@@ -2222,6 +2218,17 @@
                         fs.nesting = 0;
                         fs.aggregateTime += nowELAPSED - fs.startTime;
                     }
+                    if (RECORD_ALARMS_IN_HISTORY) {
+                        if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
+                            for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
+                                ActivityManagerNative.noteAlarmFinish(
+                                        pi, inflight.mWorkSource.get(wi), inflight.mTag);
+                            }
+                        } else {
+                            ActivityManagerNative.noteAlarmFinish(
+                                    pi, -1, inflight.mTag);
+                        }
+                    }
                 } else {
                     mLog.w("No in-flight alarm for " + pi + " " + intent);
                 }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 53c87a2..ee73b1a 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -44,12 +44,14 @@
 import android.provider.Settings.Secure;
 import android.provider.Settings.SettingNotFoundException;
 import android.security.KeyStore;
+import android.service.gatekeeper.IGateKeeperService;
 import android.text.TextUtils;
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.server.LockSettingsStorage.CredentialHash;
 
 import java.util.Arrays;
 import java.util.List;
@@ -72,6 +74,7 @@
 
     private LockPatternUtils mLockPatternUtils;
     private boolean mFirstCallToVold;
+    private IGateKeeperService mGateKeeperService;
 
     public LockSettingsService(Context context) {
         mContext = context;
@@ -131,6 +134,7 @@
 
     public void systemReady() {
         migrateOldData();
+        getGateKeeperService();
         mStorage.prefetchUser(UserHandle.USER_OWNER);
     }
 
@@ -277,7 +281,6 @@
     @Override
     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
         checkReadPermission(key, userId);
-
         String value = getStringUnchecked(key, null, userId);
         return TextUtils.isEmpty(value) ?
                 defaultValue : (value.equals("1") || value.equals("true"));
@@ -345,62 +348,252 @@
         }
     }
 
-    @Override
-    public void setLockPattern(String pattern, int userId) throws RemoteException {
-        checkWritePermission(userId);
 
-        maybeUpdateKeystore(pattern, userId);
+    private byte[] getCurrentHandle(int userId) {
+        CredentialHash credential;
+        byte[] currentHandle;
 
-        final byte[] hash = LockPatternUtils.patternToHash(
-                LockPatternUtils.stringToPattern(pattern));
-        mStorage.writePatternHash(hash, userId);
+        int currentHandleType = mStorage.getStoredCredentialType(userId);
+        switch (currentHandleType) {
+            case CredentialHash.TYPE_PATTERN:
+                credential = mStorage.readPatternHash(userId);
+                currentHandle = credential != null
+                        ? credential.hash
+                        : null;
+                break;
+            case CredentialHash.TYPE_PASSWORD:
+                credential = mStorage.readPasswordHash(userId);
+                currentHandle = credential != null
+                        ? credential.hash
+                        : null;
+                break;
+            case CredentialHash.TYPE_NONE:
+            default:
+                currentHandle = null;
+                break;
+        }
+
+        // sanity check
+        if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
+            Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
+        }
+
+        return currentHandle;
     }
 
+
     @Override
-    public void setLockPassword(String password, int userId) throws RemoteException {
+    public void setLockPattern(String pattern, String savedCredential, int userId)
+            throws RemoteException {
+        byte[] currentHandle = getCurrentHandle(userId);
+
+        if (pattern == null) {
+            mStorage.writePatternHash(null, userId);
+            return;
+        }
+
+        if (currentHandle == null) {
+            if (savedCredential != null) {
+                Slog.w(TAG, "Saved credential provided, but none stored");
+            }
+            savedCredential = null;
+        }
+
+        byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
+        if (enrolledHandle != null) {
+            mStorage.writePatternHash(enrolledHandle, userId);
+        } else {
+            Slog.e(TAG, "Failed to enroll pattern");
+        }
+    }
+
+
+    @Override
+    public void setLockPassword(String password, String savedCredential, int userId)
+            throws RemoteException {
+        byte[] currentHandle = getCurrentHandle(userId);
+
+        if (password == null) {
+            mStorage.writePasswordHash(null, userId);
+            return;
+        }
+
+        if (currentHandle == null) {
+            if (savedCredential != null) {
+                Slog.w(TAG, "Saved credential provided, but none stored");
+            }
+            savedCredential = null;
+        }
+
+        byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
+        if (enrolledHandle != null) {
+            mStorage.writePasswordHash(enrolledHandle, userId);
+        } else {
+            Slog.e(TAG, "Failed to enroll password");
+        }
+    }
+
+    private byte[] enrollCredential(byte[] enrolledHandle,
+            String enrolledCredential, String toEnroll, int userId)
+            throws RemoteException {
         checkWritePermission(userId);
+        byte[] enrolledCredentialBytes = enrolledCredential == null
+                ? null
+                : enrolledCredential.getBytes();
+        byte[] toEnrollBytes = toEnroll == null
+                ? null
+                : toEnroll.getBytes();
+        byte[] hash = getGateKeeperService().enroll(userId, enrolledHandle, enrolledCredentialBytes,
+                toEnrollBytes);
 
-        maybeUpdateKeystore(password, userId);
+        if (hash != null) {
+            maybeUpdateKeystore(toEnroll, userId);
+        }
 
-        mStorage.writePasswordHash(mLockPatternUtils.passwordToHash(password, userId), userId);
+        return hash;
     }
 
     @Override
     public boolean checkPattern(String pattern, int userId) throws RemoteException {
-        checkPasswordReadPermission(userId);
-        byte[] hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(pattern));
-        byte[] storedHash = mStorage.readPatternHash(userId);
-
-        if (storedHash == null) {
-            return true;
+        try {
+            doVerifyPattern(pattern, false, 0, userId);
+        } catch (VerificationFailedException ex) {
+            return false;
         }
 
-        boolean matched = Arrays.equals(hash, storedHash);
-        if (matched && !TextUtils.isEmpty(pattern)) {
-            maybeUpdateKeystore(pattern, userId);
+        return true;
+    }
+
+    @Override
+    public byte[] verifyPattern(String pattern, long challenge, int userId)
+            throws RemoteException {
+        try {
+            return doVerifyPattern(pattern, true, challenge, userId);
+        } catch (VerificationFailedException ex) {
+            return null;
         }
-        return matched;
+    }
+
+    private byte[] doVerifyPattern(String pattern, boolean hasChallenge, long challenge,
+            int userId) throws VerificationFailedException, RemoteException {
+       checkPasswordReadPermission(userId);
+
+       CredentialHash storedHash = mStorage.readPatternHash(userId);
+
+        if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(pattern)) {
+            // don't need to pass empty passwords to GateKeeper
+            return null;
+        }
+
+        if (TextUtils.isEmpty(pattern)) {
+            throw new VerificationFailedException();
+        }
+
+        if (storedHash.version == CredentialHash.VERSION_LEGACY) {
+            byte[] hash = mLockPatternUtils.patternToHash(
+                    mLockPatternUtils.stringToPattern(pattern));
+            if (Arrays.equals(hash, storedHash.hash)) {
+                maybeUpdateKeystore(pattern, userId);
+                // migrate password to GateKeeper
+                setLockPattern(pattern, null, userId);
+                if (!hasChallenge) {
+                    return null;
+                }
+                // Fall through to get the auth token. Technically this should never happen,
+                // as a user that had a legacy pattern would have to unlock their device
+                // before getting to a flow with a challenge, but supporting for consistency.
+            } else {
+                throw new VerificationFailedException();
+            }
+        }
+
+        byte[] token = null;
+        if (hasChallenge) {
+            token = getGateKeeperService()
+                    .verifyChallenge(userId, challenge, storedHash.hash, pattern.getBytes());
+            if (token == null) {
+                throw new VerificationFailedException();
+            }
+        } else if (!getGateKeeperService().verify(userId, storedHash.hash, pattern.getBytes())) {
+            throw new VerificationFailedException();
+        }
+
+        // pattern has matched
+        maybeUpdateKeystore(pattern, userId);
+        return token;
+
     }
 
     @Override
     public boolean checkPassword(String password, int userId) throws RemoteException {
-        checkPasswordReadPermission(userId);
-
-        byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
-        byte[] storedHash = mStorage.readPasswordHash(userId);
-
-        if (storedHash == null) {
-            return true;
+        try {
+            doVerifyPassword(password, false, 0, userId);
+        } catch (VerificationFailedException ex) {
+            return false;
         }
-
-        boolean matched = Arrays.equals(hash, storedHash);
-        if (matched && !TextUtils.isEmpty(password)) {
-            maybeUpdateKeystore(password, userId);
-        }
-        return matched;
+        return true;
     }
 
     @Override
+    public byte[] verifyPassword(String password, long challenge, int userId)
+            throws RemoteException {
+        try {
+            return doVerifyPassword(password, true, challenge, userId);
+        } catch (VerificationFailedException ex) {
+            return null;
+        }
+    }
+
+    private byte[] doVerifyPassword(String password, boolean hasChallenge, long challenge,
+            int userId) throws VerificationFailedException, RemoteException {
+       checkPasswordReadPermission(userId);
+
+       CredentialHash storedHash = mStorage.readPasswordHash(userId);
+
+        if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(password)) {
+            // don't need to pass empty passwords to GateKeeper
+            return null;
+        }
+
+        if (TextUtils.isEmpty(password)) {
+            throw new VerificationFailedException();
+        }
+
+        if (storedHash.version == CredentialHash.VERSION_LEGACY) {
+            byte[] hash = mLockPatternUtils.passwordToHash(password, userId);
+            if (Arrays.equals(hash, storedHash.hash)) {
+                maybeUpdateKeystore(password, userId);
+                // migrate password to GateKeeper
+                setLockPassword(password, null, userId);
+                if (!hasChallenge) {
+                    return null;
+                }
+                // Fall through to get the auth token. Technically this should never happen,
+                // as a user that had a legacy password would have to unlock their device
+                // before getting to a flow with a challenge, but supporting for consistency.
+            } else {
+                throw new VerificationFailedException();
+            }
+        }
+
+        byte[] token = null;
+        if (hasChallenge) {
+            token = getGateKeeperService()
+                    .verifyChallenge(userId, challenge, storedHash.hash, password.getBytes());
+            if (token == null) {
+                throw new VerificationFailedException();
+            }
+        } else if (!getGateKeeperService().verify(userId, storedHash.hash, password.getBytes())) {
+            throw new VerificationFailedException();
+        }
+
+        // password has matched
+        maybeUpdateKeystore(password, userId);
+        return token;
+    }
+
+
+    @Override
     public boolean checkVoldPassword(int userId) throws RemoteException {
         if (!mFirstCallToVold) {
             return false;
@@ -482,6 +675,7 @@
     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
             LockPatternUtils.PASSWORD_HISTORY_KEY,
+            LockPatternUtils.PASSWORD_TYPE_KEY,
     };
 
     private static final String[] SETTINGS_TO_BACKUP = new String[] {
@@ -496,4 +690,23 @@
         }
         return null;
     }
+
+    private synchronized IGateKeeperService getGateKeeperService() {
+        if (mGateKeeperService != null) {
+            return mGateKeeperService;
+        }
+
+        final IBinder service =
+            ServiceManager.getService("android.service.gatekeeper.IGateKeeperService");
+        if (service != null) {
+            mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
+            return mGateKeeperService;
+        }
+
+        Slog.e(TAG, "Unable to acquire GateKeeperService");
+        return null;
+    }
+
+    private class VerificationFailedException extends Exception {}
+
 }
diff --git a/services/core/java/com/android/server/LockSettingsStorage.java b/services/core/java/com/android/server/LockSettingsStorage.java
index d81daa9..f202c36 100644
--- a/services/core/java/com/android/server/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/LockSettingsStorage.java
@@ -56,8 +56,10 @@
     };
 
     private static final String SYSTEM_DIRECTORY = "/system/";
-    private static final String LOCK_PATTERN_FILE = "gesture.key";
-    private static final String LOCK_PASSWORD_FILE = "password.key";
+    private static final String LOCK_PATTERN_FILE = "gatekeeper.gesture.key";
+    private static final String LEGACY_LOCK_PATTERN_FILE = "gesture.key";
+    private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key";
+    private static final String LEGACY_LOCK_PASSWORD_FILE = "password.key";
 
     private static final Object DEFAULT = new Object();
 
@@ -66,6 +68,25 @@
     private final Cache mCache = new Cache();
     private final Object mFileWriteLock = new Object();
 
+    private int mStoredCredentialType;
+
+    class CredentialHash {
+        static final int TYPE_NONE = -1;
+        static final int TYPE_PATTERN = 1;
+        static final int TYPE_PASSWORD = 2;
+
+        static final int VERSION_LEGACY = 0;
+        static final int VERSION_GATEKEEPER = 1;
+
+        CredentialHash(byte[] hash, int version) {
+            this.hash = hash;
+            this.version = version;
+        }
+
+        byte[] hash;
+        int version;
+    }
+
     public LockSettingsStorage(Context context, Callback callback) {
         mContext = context;
         mOpenHelper = new DatabaseHelper(context, callback);
@@ -148,28 +169,72 @@
         readPatternHash(userId);
     }
 
-    public byte[] readPasswordHash(int userId) {
-        final byte[] stored = readFile(getLockPasswordFilename(userId));
-        if (stored != null && stored.length > 0) {
-            return stored;
+    public int getStoredCredentialType(int userId) {
+        if (mStoredCredentialType != 0) {
+            return mStoredCredentialType;
         }
+
+        CredentialHash pattern = readPatternHash(userId);
+        if (pattern == null) {
+            if (readPasswordHash(userId) != null) {
+                mStoredCredentialType = CredentialHash.TYPE_PASSWORD;
+            } else {
+                mStoredCredentialType = CredentialHash.TYPE_NONE;
+            }
+        } else {
+            CredentialHash password = readPasswordHash(userId);
+            if (password != null) {
+                // Both will never be GateKeeper
+                if (password.version == CredentialHash.VERSION_GATEKEEPER) {
+                    mStoredCredentialType = CredentialHash.TYPE_PASSWORD;
+                } else {
+                    mStoredCredentialType = CredentialHash.TYPE_PATTERN;
+                }
+            } else {
+                mStoredCredentialType = CredentialHash.TYPE_PATTERN;
+            }
+        }
+
+        return mStoredCredentialType;
+    }
+
+
+    public CredentialHash readPasswordHash(int userId) {
+        byte[] stored = readFile(getLockPasswordFilename(userId));
+        if (stored != null && stored.length > 0) {
+            return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER);
+        }
+
+        stored = readFile(getLegacyLockPasswordFilename(userId));
+        if (stored != null && stored.length > 0) {
+            return new CredentialHash(stored, CredentialHash.VERSION_LEGACY);
+        }
+
         return null;
     }
 
-    public byte[] readPatternHash(int userId) {
-        final byte[] stored = readFile(getLockPatternFilename(userId));
+    public CredentialHash readPatternHash(int userId) {
+        byte[] stored = readFile(getLockPatternFilename(userId));
         if (stored != null && stored.length > 0) {
-            return stored;
+            return new CredentialHash(stored, CredentialHash.VERSION_GATEKEEPER);
         }
+
+        stored = readFile(getLegacyLockPatternFilename(userId));
+        if (stored != null && stored.length > 0) {
+            return new CredentialHash(stored, CredentialHash.VERSION_LEGACY);
+        }
+
         return null;
     }
 
     public boolean hasPassword(int userId) {
-        return hasFile(getLockPasswordFilename(userId));
+        return hasFile(getLockPasswordFilename(userId)) ||
+            hasFile(getLegacyLockPasswordFilename(userId));
     }
 
     public boolean hasPattern(int userId) {
-        return hasFile(getLockPatternFilename(userId));
+        return hasFile(getLockPatternFilename(userId)) ||
+            hasFile(getLegacyLockPatternFilename(userId));
     }
 
     private boolean hasFile(String name) {
@@ -237,6 +302,9 @@
     }
 
     public void writePatternHash(byte[] hash, int userId) {
+        mStoredCredentialType = hash == null
+            ? CredentialHash.TYPE_NONE
+            : CredentialHash.TYPE_PATTERN;
         writeFile(getLockPatternFilename(userId), hash);
         clearPasswordHash(userId);
     }
@@ -246,6 +314,9 @@
     }
 
     public void writePasswordHash(byte[] hash, int userId) {
+        mStoredCredentialType = hash == null
+            ? CredentialHash.TYPE_NONE
+            : CredentialHash.TYPE_PASSWORD;
         writeFile(getLockPasswordFilename(userId), hash);
         clearPatternHash(userId);
     }
@@ -264,6 +335,16 @@
         return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE);
     }
 
+    @VisibleForTesting
+    String getLegacyLockPatternFilename(int userId) {
+        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PATTERN_FILE);
+    }
+
+    @VisibleForTesting
+    String getLegacyLockPasswordFilename(int userId) {
+        return getLockCredentialFilePathForUser(userId, LEGACY_LOCK_PASSWORD_FILE);
+    }
+
     private String getLockCredentialFilePathForUser(int userId, String basename) {
         userId = getUserParentOrSelfId(userId);
         String dataSystemDirectory =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6341807..b606353 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -42,7 +42,6 @@
 import android.app.ITaskStackListener;
 import android.app.ProfilerInfo;
 import android.app.usage.UsageEvents;
-import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.content.res.Resources;
@@ -3449,6 +3448,35 @@
         }
     }
 
+    @Override
+    public int getPackageProcessState(String packageName) {
+        int procState = ActivityManager.PROCESS_STATE_NONEXISTENT;
+        synchronized (this) {
+            for (int i=mLruProcesses.size()-1; i>=0; i--) {
+                final ProcessRecord proc = mLruProcesses.get(i);
+                if (procState == ActivityManager.PROCESS_STATE_NONEXISTENT
+                        || procState > proc.setProcState) {
+                    boolean found = false;
+                    for (int j=proc.pkgList.size()-1; j>=0 && !found; j--) {
+                        if (proc.pkgList.keyAt(j).equals(packageName)) {
+                            procState = proc.setProcState;
+                            found = true;
+                        }
+                    }
+                    if (proc.pkgDeps != null && !found) {
+                        for (int j=proc.pkgDeps.size()-1; j>=0; j--) {
+                            if (proc.pkgDeps.valueAt(j).equals(packageName)) {
+                                procState = proc.setProcState;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return procState;
+    }
+
     private void dispatchProcessesChanged() {
         int N;
         synchronized (this) {
@@ -10501,15 +10529,11 @@
                 Context.WINDOW_SERVICE)).addView(v, lp);
     }
 
-    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg) {
+    public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag) {
         if (!(sender instanceof PendingIntentRecord)) {
             return;
         }
         final PendingIntentRecord rec = (PendingIntentRecord)sender;
-        final String tag;
-        synchronized (this) {
-            tag = getTagForIntentSenderLocked(rec, "*walarm*:");
-        }
         final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         synchronized (stats) {
             if (mBatteryStatsService.isOnBattery()) {
@@ -10524,6 +10548,34 @@
         }
     }
 
+    public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag) {
+        if (!(sender instanceof PendingIntentRecord)) {
+            return;
+        }
+        final PendingIntentRecord rec = (PendingIntentRecord)sender;
+        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        synchronized (stats) {
+            mBatteryStatsService.enforceCallingPermission();
+            int MY_UID = Binder.getCallingUid();
+            int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+            mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
+        }
+    }
+
+    public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag) {
+        if (!(sender instanceof PendingIntentRecord)) {
+            return;
+        }
+        final PendingIntentRecord rec = (PendingIntentRecord)sender;
+        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        synchronized (stats) {
+            mBatteryStatsService.enforceCallingPermission();
+            int MY_UID = Binder.getCallingUid();
+            int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+            mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
+        }
+    }
+
     public boolean killPids(int[] pids, String pReason, boolean secure) {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("killPids only available to the system");
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index ed108c2..bfc4fc7 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -315,6 +315,20 @@
         }
     }
 
+    public void noteAlarmStart(String name, int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteAlarmStartLocked(name, uid);
+        }
+    }
+
+    public void noteAlarmFinish(String name, int uid) {
+        enforceCallingPermission();
+        synchronized (mStats) {
+            mStats.noteAlarmFinishLocked(name, uid);
+        }
+    }
+
     public void noteStartWakelock(int uid, int pid, String name, String historyName, int type,
             boolean unimportantForLogging) {
         enforceCallingPermission();
@@ -884,7 +898,7 @@
         pw.println("    Enable or disable a running option.  Option state is not saved across boots.");
         pw.println("    Options are:");
         pw.println("      full-history: include additional detailed events in battery history:");
-        pw.println("          wake_lock_in and proc events");
+        pw.println("          wake_lock_in, alarms and proc events");
         pw.println("      no-auto-reset: don't automatically reset stats when unplugged");
     }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 1eddc8e..9a30f0d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5577,8 +5577,9 @@
     @Override
     public void setVolumePolicy(VolumePolicy policy) {
         enforceVolumeController("set volume policy");
-        if (policy != null) {
+        if (policy != null && !policy.equals(mVolumePolicy)) {
             mVolumePolicy = policy;
+            if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
         }
     }
 
diff --git a/services/core/java/com/android/server/content/AppIdleMonitor.java b/services/core/java/com/android/server/content/AppIdleMonitor.java
new file mode 100644
index 0000000..9598de8
--- /dev/null
+++ b/services/core/java/com/android/server/content/AppIdleMonitor.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.content;
+
+import android.app.usage.UsageStatsManagerInternal;
+import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+
+import com.android.server.LocalServices;
+
+/**
+ * Helper to listen for app idle and charging status changes and restart backed off
+ * sync operations.
+ */
+class AppIdleMonitor implements AppIdleStateChangeListener {
+
+    private final SyncManager mSyncManager;
+    private final UsageStatsManagerInternal mUsageStats;
+    final BatteryManager mBatteryManager;
+    /** Is the device currently plugged into power. */
+    private boolean mPluggedIn;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            onPluggedIn(mBatteryManager.isCharging());
+        }
+    };
+
+    AppIdleMonitor(SyncManager syncManager, Context context) {
+        mSyncManager = syncManager;
+        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+        mUsageStats.addAppIdleStateChangeListener(this);
+        mBatteryManager = context.getSystemService(BatteryManager.class);
+        mPluggedIn = isPowered();
+        registerReceivers(context);
+    }
+
+    private void registerReceivers(Context context) {
+        // Monitor battery charging state
+        IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
+        filter.addAction(BatteryManager.ACTION_DISCHARGING);
+        context.registerReceiver(mReceiver, filter);
+    }
+
+    private boolean isPowered() {
+        return mBatteryManager.isCharging();
+    }
+
+    void onPluggedIn(boolean pluggedIn) {
+        if (mPluggedIn == pluggedIn) {
+            return;
+        }
+        mPluggedIn = pluggedIn;
+        if (mPluggedIn) {
+            mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL);
+        }
+    }
+
+    boolean isAppIdle(String packageName, int userId) {
+        return !mPluggedIn && mUsageStats.isAppIdle(packageName, userId);
+    }
+
+    @Override
+    public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+        // Don't care if the app is becoming idle
+        if (idle) return;
+        mSyncManager.onAppNotIdle(packageName, userId);
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 7866ddc..4173b78 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -83,6 +83,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.accounts.AccountManagerService;
 import com.android.server.content.SyncStorageEngine.AuthorityInfo;
+import com.android.server.content.SyncStorageEngine.EndPoint;
 import com.android.server.content.SyncStorageEngine.OnSyncRequestListener;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -107,7 +108,7 @@
  * @hide
  */
 public class SyncManager {
-    private static final String TAG = "SyncManager";
+    static final String TAG = "SyncManager";
 
     /** Delay a sync due to local changes this long. In milliseconds */
     private static final long LOCAL_SYNC_DELAY;
@@ -199,6 +200,8 @@
 
     protected SyncAdaptersCache mSyncAdapters;
 
+    private final AppIdleMonitor mAppIdleMonitor;
+
     private BroadcastReceiver mStorageIntentReceiver =
             new BroadcastReceiver() {
                 @Override
@@ -427,6 +430,8 @@
         mSyncAlarmIntent = PendingIntent.getBroadcast(
                 mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
 
+        mAppIdleMonitor = new AppIdleMonitor(this, mContext);
+
         IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
         context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
 
@@ -1169,6 +1174,36 @@
     }
 
     /**
+     * Clear backoff on operations in the sync queue that match the packageName and userId.
+     * @param packageName The package that just became active. Can be null to indicate that all
+     * packages are now considered active due to being plugged in.
+     * @param userId The user for which the package has become active. Can be USER_ALL if
+     * the device just plugged in.
+     */
+    void onAppNotIdle(String packageName, int userId) {
+        synchronized (mSyncQueue) {
+            // For all sync operations in sync queue, if marked as idle, compare with package name
+            // and unmark. And clear backoff for the operation.
+            final Iterator<SyncOperation> operationIterator =
+                    mSyncQueue.getOperations().iterator();
+            boolean changed = false;
+            while (operationIterator.hasNext()) {
+                final SyncOperation op = operationIterator.next();
+                if (op.appIdle
+                        && getPackageName(op.target).equals(packageName)
+                        && (userId == UserHandle.USER_ALL || op.target.userId == userId)) {
+                    op.appIdle = false;
+                    clearBackoffSetting(op);
+                    changed = true;
+                }
+            }
+            if (changed) {
+                sendCheckAlarmsMessage();
+            }
+        }
+    }
+
+    /**
      * @hide
      */
     class ActiveSyncContext extends ISyncContext.Stub
@@ -2447,6 +2482,19 @@
                         }
                         continue;
                     }
+                    String packageName = getPackageName(op.target);
+                    // If app is considered idle, then skip for now and backoff
+                    if (packageName != null
+                            && mAppIdleMonitor.isAppIdle(packageName, op.target.userId)) {
+                        increaseBackoffSetting(op);
+                        op.appIdle = true;
+                        if (isLoggable) {
+                            Log.v(TAG, "Sync backing off idle app " + packageName);
+                        }
+                        continue;
+                    } else {
+                        op.appIdle = false;
+                    }
                     // Add this sync to be run.
                     operations.add(op);
                 }
@@ -3194,6 +3242,21 @@
         }
     }
 
+    String getPackageName(EndPoint endpoint) {
+        if (endpoint.target_service) {
+            return endpoint.service.getPackageName();
+        } else {
+            SyncAdapterType syncAdapterType =
+                    SyncAdapterType.newKey(endpoint.provider, endpoint.account.type);
+            final RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo;
+            syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType, endpoint.userId);
+            if (syncAdapterInfo == null) {
+                return null;
+            }
+            return syncAdapterInfo.componentName.getPackageName();
+        }
+    }
+
     private boolean isSyncStillActive(ActiveSyncContext activeSyncContext) {
         for (ActiveSyncContext sync : mActiveSyncContexts) {
             if (sync == activeSyncContext) {
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index 35827cc..10efe81 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -90,6 +90,9 @@
     /** Descriptive string key for this operation */
     public String wakeLockName;
 
+    /** Whether this sync op was recently skipped due to the app being idle */
+    public boolean appIdle;
+
     public SyncOperation(Account account, int userId, int reason, int source, String provider,
             Bundle extras, long runTimeFromNow, long flexTime, long backoff,
             long delayUntil, boolean allowParallelSyncs) {
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 8a9f3e1..23d5c05 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -49,16 +49,12 @@
     private static volatile AppIdleController sController;
     final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     private final UsageStatsManagerInternal mUsageStatsInternal;
-    private final BatteryManagerInternal mBatteryManagerInternal;
+    private final BatteryManager mBatteryManager;
     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);
-            }
+            onPluggedIn(mBatteryManager.isCharging());
         }
     };
 
@@ -74,23 +70,19 @@
     private AppIdleController(StateChangedListener stateChangedListener, Context context) {
         super(stateChangedListener, context);
         mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
-        mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
-        mPluggedIn = isPowered();
+        mBatteryManager = context.getSystemService(BatteryManager.class);
+        mPluggedIn = mBatteryManager.isCharging();
         mUsageStatsInternal.addAppIdleStateChangeListener(this);
         registerReceivers();
     }
 
     private void registerReceivers() {
         // Monitor battery charging state
-        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+        IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
+        filter.addAction(BatteryManager.ACTION_DISCHARGING);
         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) {
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index 530ad4b..834dff2 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -44,6 +44,9 @@
 public class FlpHardwareProvider {
     private GeofenceHardwareImpl mGeofenceHardwareSink = null;
     private IFusedLocationHardwareSink mLocationSink = null;
+    // Capabilities provided by FlpCallbacks
+    private boolean mHaveBatchingCapabilities;
+    private int mBatchingCapabilities;
 
     private static FlpHardwareProvider sSingletonInstance = null;
 
@@ -124,6 +127,47 @@
         }
     }
 
+    private void onBatchingCapabilities(int capabilities) {
+        synchronized (mLocationSinkLock) {
+            mHaveBatchingCapabilities = true;
+            mBatchingCapabilities = capabilities;
+        }
+
+        maybeSendCapabilities();
+    }
+
+    private void onBatchingStatus(int status) {
+        IFusedLocationHardwareSink sink;
+        synchronized (mLocationSinkLock) {
+            sink = mLocationSink;
+        }
+        try {
+            if (sink != null) {
+                sink.onStatusChanged(status);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling onBatchingStatus");
+        }
+    }
+
+    private void maybeSendCapabilities() {
+        IFusedLocationHardwareSink sink;
+        boolean haveBatchingCapabilities;
+        int batchingCapabilities;
+        synchronized (mLocationSinkLock) {
+            sink = mLocationSink;
+            haveBatchingCapabilities = mHaveBatchingCapabilities;
+            batchingCapabilities = mBatchingCapabilities;
+        }
+        try {
+            if (sink != null && haveBatchingCapabilities) {
+                sink.onCapabilities(batchingCapabilities);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException calling onLocationAvailable");
+        }
+    }
+
     // FlpDiagnosticCallbacks members
     private void onDataReport(String data) {
         IFusedLocationHardwareSink sink;
@@ -209,6 +253,10 @@
                 translateToGeofenceHardwareStatus(result));
     }
 
+    private void onGeofencingCapabilities(int capabilities) {
+        getGeofenceHardwareSink().onCapabilities(capabilities);
+    }
+
     /**
      * Private native methods accessing FLP HAL.
      */
@@ -225,6 +273,7 @@
     private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
     private native void nativeStopBatching(int id);
     private native void nativeRequestBatchedLocation(int lastNLocations);
+    private native void nativeFlushBatchedLocations();
     private native void nativeInjectLocation(Location location);
     // TODO [Fix] sort out the lifetime of the instance
     private native void nativeCleanup();
@@ -277,6 +326,7 @@
 
                 mLocationSink = eventSink;
             }
+            maybeSendCapabilities();
         }
 
         @Override
@@ -315,6 +365,11 @@
         }
 
         @Override
+        public void flushBatchedLocations() {
+            nativeFlushBatchedLocations();
+        }
+
+        @Override
         public boolean supportsDiagnosticDataInjection() {
             return nativeIsDiagnosticSupported();
         }
diff --git a/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
index 389bd24..e49c411 100644
--- a/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
+++ b/services/core/java/com/android/server/location/FusedLocationHardwareSecure.java
@@ -116,4 +116,10 @@
         checkPermissions();
         mLocationHardware.injectDeviceContext(deviceEnabledContext);
     }
+
+    @Override
+    public void flushBatchedLocations() throws RemoteException {
+        checkPermissions();
+        mLocationHardware.flushBatchedLocations();
+    }
 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index fc2eced..b36fcd2 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -142,6 +142,9 @@
         } catch (RemoteException e) {
             // we tried
         }
+        if (mCallback != null) {
+            mCallback.onServiceAdded(info.component);
+        }
     }
 
     @Override
@@ -246,6 +249,16 @@
         }
     }
 
+    public IConditionProvider findConditionProvider(ComponentName component) {
+        if (component == null) return null;
+        for (ManagedServiceInfo service : mServices) {
+            if (component.equals(service.component)) {
+                return provider(service);
+            }
+        }
+        return null;
+    }
+
     public void ensureRecordExists(ComponentName component, Uri conditionId,
             IConditionProvider provider) {
         // constructed by convention, make sure the record exists...
@@ -378,6 +391,7 @@
 
     public interface Callback {
         void onBootComplete();
+        void onServiceAdded(ComponentName component);
         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 d223353..6a04688c 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -38,7 +38,7 @@
 
 /** Built-in zen condition provider for simple time-based conditions */
 public class CountdownConditionProvider extends SystemConditionProviderService {
-    private static final String TAG = "CountdownConditions";
+    private static final String TAG = "ConditionProviders";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     public static final ComponentName COMPONENT =
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index c997e45..383d56c 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -43,7 +43,7 @@
  * 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 String TAG = "ConditionProviders";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     public static final ComponentName COMPONENT =
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 67a2a54..766d6c5 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -20,6 +20,7 @@
 import android.net.Uri;
 import android.service.notification.Condition;
 import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
 import android.util.ArrayMap;
@@ -39,6 +40,7 @@
 
     private CountdownConditionProvider mCountdown;
     private ScheduleConditionProvider mSchedule;
+    private boolean mFirstEvaluation = true;
 
     public ZenModeConditions(ZenModeHelper helper, ConditionProviders conditionProviders) {
         mHelper = helper;
@@ -64,7 +66,8 @@
 
     public void evaluateConfig(ZenModeConfig config) {
         if (config == null) return;
-        if (config.manualRule != null && !config.manualRule.isTrueOrUnknown()) {
+        if (config.manualRule != null && config.manualRule.condition != null
+                && !config.manualRule.isTrueOrUnknown()) {
             if (DEBUG) Log.d(TAG, "evaluateConfig: clearing manual rule");
             config.manualRule = null;
         }
@@ -72,6 +75,7 @@
         evaluateRule(config.manualRule, current);
         for (ZenRule automaticRule : config.automaticRules.values()) {
             evaluateRule(automaticRule, current);
+            updateSnoozing(automaticRule);
         }
         final int N = mSubscriptions.size();
         for (int i = N - 1; i >= 0; i--) {
@@ -82,21 +86,7 @@
                 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);
-        }
+        mFirstEvaluation = false;
     }
 
     @Override
@@ -110,6 +100,14 @@
     }
 
     @Override
+    public void onServiceAdded(ComponentName component) {
+        if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
+        if (isAutomaticActive(component)) {
+            mHelper.setConfig(mHelper.getConfig(), "zmc.onServiceAdded");
+        }
+    }
+
+    @Override
     public void onConditionChanged(Uri id, Condition condition) {
         if (DEBUG) Log.d(TAG, "onConditionChanged " + id + " " + condition);
         ZenModeConfig config = mHelper.getConfig();
@@ -125,8 +123,53 @@
         }
     }
 
+    private void evaluateRule(ZenRule rule, ArraySet<Uri> current) {
+        if (rule == null || rule.conditionId == null) return;
+        final Uri id = rule.conditionId;
+        boolean isSystemCondition = false;
+        for (SystemConditionProviderService sp : mConditionProviders.getSystemProviders()) {
+            if (sp.isValidConditionid(id)) {
+                mConditionProviders.ensureRecordExists(sp.getComponent(), id, sp.asInterface());
+                rule.component = sp.getComponent();
+                isSystemCondition = true;
+            }
+        }
+        if (!isSystemCondition) {
+            final IConditionProvider cp = mConditionProviders.findConditionProvider(rule.component);
+            if (DEBUG) Log.d(TAG, "Ensure external rule exists: " + (cp != null) + " for " + id);
+            if (cp != null) {
+                mConditionProviders.ensureRecordExists(rule.component, id, cp);
+            }
+        }
+        if (rule.component == null) {
+            Log.w(TAG, "No component found for automatic rule: " + rule.conditionId);
+            rule.enabled = false;
+            return;
+        }
+        if (current != null) {
+            current.add(id);
+        }
+        if (mConditionProviders.subscribeIfNecessary(rule.component, rule.conditionId)) {
+            mSubscriptions.put(rule.conditionId, rule.component);
+        } else {
+            if (DEBUG) Log.d(TAG, "zmc failed to subscribe");
+        }
+    }
+
+    private boolean isAutomaticActive(ComponentName component) {
+        if (component == null) return false;
+        final ZenModeConfig config = mHelper.getConfig();
+        if (config == null) return false;
+        for (ZenRule rule : config.automaticRules.values()) {
+            if (component.equals(rule.component) && rule.isAutomaticActive()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private boolean updateSnoozing(ZenRule rule) {
-        if (rule != null && rule.snoozing && !rule.isTrueOrUnknown()) {
+        if (rule != null && rule.snoozing && (mFirstEvaluation || !rule.isTrueOrUnknown())) {
             rule.snoozing = false;
             if (DEBUG) Log.d(TAG, "Snoozing reset for " + rule.conditionId);
             return true;
@@ -141,4 +184,5 @@
         rule.condition = condition;
         return true;
     }
+
 }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index e5925fe..40218bb 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -175,7 +175,7 @@
         if (zenMode == Global.ZEN_MODE_OFF) {
             newConfig.manualRule = null;
             for (ZenRule automaticRule : newConfig.automaticRules.values()) {
-                if (automaticRule.isTrueOrUnknown()) {
+                if (automaticRule.isAutomaticActive()) {
                     automaticRule.snoozing = true;
                 }
             }
@@ -286,8 +286,7 @@
         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 (automaticRule.isAutomaticActive()) {
                 if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
                     zen = automaticRule.zenMode;
                 }
@@ -502,7 +501,7 @@
                     if (isChange && policy.doNotDisturbWhenSilent) {
                         if (mZenMode != Global.ZEN_MODE_NO_INTERRUPTIONS
                                 && mZenMode != Global.ZEN_MODE_ALARMS) {
-                            newZen = Global.ZEN_MODE_NO_INTERRUPTIONS;
+                            newZen = Global.ZEN_MODE_ALARMS;
                         }
                     }
                     break;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index cd1c9a5..b38d33d 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -691,6 +691,20 @@
             return isDeviceLockedInner(userId);
         }
 
+        @Override
+        public boolean isDeviceSecure(int userId) throws RemoteException {
+            userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
+                    false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
+            userId = resolveProfileParent(userId);
+
+            long token = Binder.clearCallingIdentity();
+            try {
+                return new LockPatternUtils(mContext).isSecure(userId);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
         private void enforceReportPermission() {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index d5508bc..852b5e9 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -33,12 +33,15 @@
 
 static jmethodID sOnLocationReport = NULL;
 static jmethodID sOnDataReport = NULL;
+static jmethodID sOnBatchingCapabilities = NULL;
+static jmethodID sOnBatchingStatus = NULL;
 static jmethodID sOnGeofenceTransition = NULL;
 static jmethodID sOnGeofenceMonitorStatus = NULL;
 static jmethodID sOnGeofenceAdd = NULL;
 static jmethodID sOnGeofenceRemove = NULL;
 static jmethodID sOnGeofencePause = NULL;
 static jmethodID sOnGeofenceResume = NULL;
+static jmethodID sOnGeofencingCapabilities = NULL;
 
 static const FlpLocationInterface* sFlpInterface = NULL;
 static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
@@ -85,6 +88,32 @@
   return true;
 }
 
+static void BatchingCapabilitiesCallback(int32_t capabilities) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnBatchingCapabilities,
+      capabilities
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void BatchingStatusCallback(int32_t status) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnBatchingStatus,
+      status
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
 static int SetThreadEvent(ThreadEvent event) {
   JavaVM* javaVm = AndroidRuntime::getJavaVM();
 
@@ -156,6 +185,18 @@
       "onDataReport",
       "(Ljava/lang/String;)V"
       );
+    sOnBatchingCapabilities = env->GetMethodID(
+        clazz,
+        "onBatchingCapabilities",
+        "(I)V");
+    sOnBatchingStatus = env->GetMethodID(
+            clazz,
+            "onBatchingStatus",
+            "(I)V");
+    sOnGeofencingCapabilities = env->GetMethodID(
+            clazz,
+            "onGeofencingCapabilities",
+            "(I)V");
   sOnGeofenceTransition = env->GetMethodID(
       clazz,
       "onGeofenceTransition",
@@ -534,7 +575,9 @@
   LocationCallback,
   AcquireWakelock,
   ReleaseWakelock,
-  SetThreadEvent
+  SetThreadEvent,
+  BatchingCapabilitiesCallback,
+  BatchingStatusCallback
 };
 
 static void ReportData(char* data, int length) {
@@ -670,6 +713,19 @@
   CheckExceptions(sCallbackEnv, __FUNCTION__);
 }
 
+static void GeofencingCapabilitiesCallback(int32_t capabilities) {
+  if(!IsValidCallbackThread()) {
+    return;
+  }
+
+  sCallbackEnv->CallVoidMethod(
+      sCallbacksObj,
+      sOnGeofencingCapabilities,
+      capabilities
+      );
+  CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
 FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
   sizeof(FlpGeofenceCallbacks),
   GeofenceTransitionCallback,
@@ -678,7 +734,8 @@
   GeofenceRemoveCallback,
   GeofencePauseCallback,
   GeofenceResumeCallback,
-  SetThreadEvent
+  SetThreadEvent,
+  GeofencingCapabilitiesCallback
 };
 
 /*
@@ -790,6 +847,14 @@
   sFlpInterface->get_batched_location(lastNLocations);
 }
 
+static void FlushBatchedLocations(JNIEnv* env, jobject /* object */) {
+  if(sFlpInterface == NULL) {
+    ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+  }
+
+  sFlpInterface->flush_batched_locations();
+}
+
 static void InjectLocation(JNIEnv* env, jobject /* object */, jobject locationObject) {
   if(locationObject == NULL) {
     ALOGE("Invalid location for injection: %p", locationObject);
@@ -972,6 +1037,9 @@
   {"nativeRequestBatchedLocation",
         "(I)V",
         reinterpret_cast<void*>(GetBatchedLocation)},
+  {"nativeFlushBatchedLocations",
+          "()V",
+          reinterpret_cast<void*>(FlushBatchedLocations)},
   {"nativeInjectLocation",
         "(Landroid/location/Location;)V",
         reinterpret_cast<void*>(InjectLocation)},
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index c766183..2661643 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Environment;
+import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -59,6 +60,7 @@
     private static final String ATTR_PACKAGE = "package";
     private static final String ATTR_COMPONENT_NAME = "component";
     private static final String ATTR_USERID = "userId";
+    private static final String TAG_OTA_POLICY = "ota-policy";
 
     private AtomicFile fileForWriting;
 
@@ -75,6 +77,9 @@
     // Internal state for the profile owner packages.
     private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
 
+    // Local OTA policy controllable by device owner.
+    private PersistableBundle mOtaPolicy;
+
     // Private default constructor.
     private DeviceOwner() {
     }
@@ -187,6 +192,18 @@
         return mProfileOwners.keySet();
     }
 
+    PersistableBundle getOtaPolicy() {
+        return mOtaPolicy;
+    }
+
+    void setOtaPolicy(PersistableBundle otaPolicy) {
+        mOtaPolicy = otaPolicy;
+    }
+
+    void clearOtaPolicy() {
+        mOtaPolicy = null;
+    }
+
     boolean hasDeviceOwner() {
         return mDeviceOwner != null;
     }
@@ -273,6 +290,8 @@
                         profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
                     }
                     mProfileOwners.put(userId, profileOwnerInfo);
+                } else if (TAG_OTA_POLICY.equals(tag)) {
+                    mOtaPolicy = PersistableBundle.restoreFromXml(parser);
                 } else {
                     throw new XmlPullParserException(
                             "Unexpected tag in device owner file: " + tag);
@@ -338,6 +357,17 @@
                     out.endTag(null, TAG_PROFILE_OWNER);
                 }
             }
+
+            // Write OTA policy tag
+            if (mOtaPolicy != null) {
+                out.startTag(null, TAG_OTA_POLICY);
+                try {
+                    mOtaPolicy.saveToXml(out);
+                } catch (XmlPullParserException e) {
+                    Slog.e(TAG, "Failed to save OTA policy", e);
+                }
+                out.endTag(null, TAG_OTA_POLICY);
+            }
             out.endDocument();
             out.flush();
             finishWrite(outputStream);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3677132..c5e1933 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -347,6 +347,8 @@
         private static final String TAG_DISABLE_KEYGUARD_FEATURES = "disable-keyguard-features";
         private static final String TAG_DISABLE_CAMERA = "disable-camera";
         private static final String TAG_DISABLE_CALLER_ID = "disable-caller-id";
+        private static final String TAG_DISABLE_BLUETOOTH_CONTACT_SHARING
+                = "disable-bt-contacts-sharing";
         private static final String TAG_DISABLE_SCREEN_CAPTURE = "disable-screen-capture";
         private static final String TAG_DISABLE_ACCOUNT_MANAGEMENT = "disable-account-management";
         private static final String TAG_REQUIRE_AUTO_TIME = "require_auto_time";
@@ -428,6 +430,7 @@
         boolean encryptionRequested = false;
         boolean disableCamera = false;
         boolean disableCallerId = false;
+        boolean disableBluetoothContactSharing = true;
         boolean disableScreenCapture = false; // Can only be set by a device/profile owner.
         boolean requireAutoTime = false; // Can only be set by a device owner.
 
@@ -569,6 +572,12 @@
                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableCallerId));
                 out.endTag(null, TAG_DISABLE_CALLER_ID);
             }
+            if (disableBluetoothContactSharing) {
+                out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
+                out.attribute(null, ATTR_VALUE,
+                        Boolean.toString(disableBluetoothContactSharing));
+                out.endTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
+            }
             if (disableScreenCapture) {
                 out.startTag(null, TAG_DISABLE_SCREEN_CAPTURE);
                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableScreenCapture));
@@ -714,6 +723,9 @@
                 } else if (TAG_DISABLE_CALLER_ID.equals(tag)) {
                     disableCallerId = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_DISABLE_BLUETOOTH_CONTACT_SHARING.equals(tag)) {
+                    disableBluetoothContactSharing = Boolean.parseBoolean(parser
+                            .getAttributeValue(null, ATTR_VALUE));
                 } else if (TAG_DISABLE_SCREEN_CAPTURE.equals(tag)) {
                     disableScreenCapture = Boolean.parseBoolean(
                             parser.getAttributeValue(null, ATTR_VALUE));
@@ -904,6 +916,8 @@
                     pw.println(disableCamera);
             pw.print(prefix); pw.print("disableCallerId=");
                     pw.println(disableCallerId);
+            pw.print(prefix); pw.print("disableBluetoothContactSharing=");
+                    pw.println(disableBluetoothContactSharing);
             pw.print(prefix); pw.print("disableScreenCapture=");
                     pw.println(disableScreenCapture);
             pw.print(prefix); pw.print("requireAutoTime=");
@@ -2799,7 +2813,7 @@
         try {
             LockPatternUtils utils = new LockPatternUtils(mContext);
             if (!TextUtils.isEmpty(password)) {
-                utils.saveLockPassword(password, quality, userHandle);
+                utils.saveLockPassword(password, null, quality, userHandle);
             } else {
                 utils.clearLock(userHandle);
             }
@@ -5522,6 +5536,46 @@
         return -1;
     }
 
+    @Override
+    public void setBluetoothContactSharingDisabled(ComponentName who, boolean disabled) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (admin.disableBluetoothContactSharing != disabled) {
+                admin.disableBluetoothContactSharing = disabled;
+                saveSettingsLocked(UserHandle.getCallingUserId());
+            }
+        }
+    }
+
+    @Override
+    public boolean getBluetoothContactSharingDisabled(ComponentName who) {
+        if (!mHasFeature) {
+            return false;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return admin.disableBluetoothContactSharing;
+        }
+    }
+
+    @Override
+    public boolean getBluetoothContactSharingDisabledForUser(int userId) {
+        // TODO: Should there be a check to make sure this relationship is
+        // within a profile group?
+        // enforceSystemProcess("getCrossProfileCallerIdDisabled can only be called by system");
+        synchronized (this) {
+            ActiveAdmin admin = getProfileOwnerAdmin(userId);
+            return (admin != null) ? admin.disableBluetoothContactSharing : false;
+        }
+    }
+
     /**
      * Sets which packages may enter lock task mode.
      *
@@ -5754,6 +5808,28 @@
         }
     }
 
+    @Override
+    public boolean setKeyguardEnabledState(ComponentName who, boolean enabled) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+        }
+        final int userId = UserHandle.getCallingUserId();
+        LockPatternUtils utils = new LockPatternUtils(mContext);
+
+        // disallow disabling the keyguard if a password is currently set
+        if (!enabled && utils.isSecure(userId)) {
+            return false;
+        }
+        long ident = Binder.clearCallingIdentity();
+        try {
+            utils.setLockScreenDisabled(!enabled, userId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+        return true;
+    }
+
     /**
      * We need to update the internal state of whether a user has completed setup once. After
      * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes
@@ -5872,4 +5948,26 @@
         }
         return admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
     }
+
+    @Override
+    public void setOtaPolicy(ComponentName who, PersistableBundle policy) {
+        synchronized (this) {
+            getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+            if (policy == null) {
+                mDeviceOwner.clearOtaPolicy();
+            } else {
+                mDeviceOwner.setOtaPolicy(policy);
+            }
+            mDeviceOwner.writeOwnerFile();
+        }
+        mContext.sendBroadcastAsUser(new Intent(DevicePolicyManager.ACTION_OTA_POLICY_CHANGED),
+                UserHandle.OWNER);
+    }
+
+    @Override
+    public PersistableBundle getOtaPolicy() {
+        synchronized (this) {
+            return mDeviceOwner.getOtaPolicy();
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
index bf0e75d..dae8447 100644
--- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java
@@ -219,31 +219,31 @@
     public void testPassword_Write() {
         mStorage.writePasswordHash("thepassword".getBytes(), 0);
 
-        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
+        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash);
         mStorage.clearCache();
-        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0));
+        assertArrayEquals("thepassword".getBytes(), mStorage.readPasswordHash(0).hash);
     }
 
     public void testPassword_WriteProfileWritesParent() {
         mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
         mStorage.writePasswordHash("profilepassword".getBytes(), 2);
 
-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash);
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash);
         mStorage.clearCache();
-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1));
-        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2));
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(1).hash);
+        assertArrayEquals("profilepassword".getBytes(), mStorage.readPasswordHash(2).hash);
     }
 
     public void testPassword_WriteParentWritesProfile() {
         mStorage.writePasswordHash("profilepassword".getBytes(), 2);
         mStorage.writePasswordHash("parentpasswordd".getBytes(), 1);
 
-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash);
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash);
         mStorage.clearCache();
-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1));
-        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2));
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(1).hash);
+        assertArrayEquals("parentpasswordd".getBytes(), mStorage.readPasswordHash(2).hash);
     }
 
     public void testPattern_Default() {
@@ -253,31 +253,31 @@
     public void testPattern_Write() {
         mStorage.writePatternHash("thepattern".getBytes(), 0);
 
-        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
+        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash);
         mStorage.clearCache();
-        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0));
+        assertArrayEquals("thepattern".getBytes(), mStorage.readPatternHash(0).hash);
     }
 
     public void testPattern_WriteProfileWritesParent() {
         mStorage.writePatternHash("parentpatternn".getBytes(), 1);
         mStorage.writePatternHash("profilepattern".getBytes(), 2);
 
-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash);
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash);
         mStorage.clearCache();
-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1));
-        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2));
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(1).hash);
+        assertArrayEquals("profilepattern".getBytes(), mStorage.readPatternHash(2).hash);
     }
 
     public void testPattern_WriteParentWritesProfile() {
         mStorage.writePatternHash("profilepattern".getBytes(), 2);
         mStorage.writePatternHash("parentpatternn".getBytes(), 1);
 
-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash);
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash);
         mStorage.clearCache();
-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1));
-        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2));
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(1).hash);
+        assertArrayEquals("parentpatternn".getBytes(), mStorage.readPatternHash(2).hash);
     }
 
     public void testPrefetch() {
@@ -289,8 +289,8 @@
         mStorage.prefetchUser(0);
 
         assertEquals("toBeFetched", mStorage.readKeyValue("key", "default", 0));
-        assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0));
-        assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0));
+        assertArrayEquals("pattern".getBytes(), mStorage.readPatternHash(0).hash);
+        assertArrayEquals("password".getBytes(), mStorage.readPasswordHash(0).hash);
     }
 
     public void testFileLocation_Owner() {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index cc0ab81..3d54dfb 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -53,6 +53,7 @@
 
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 
 import java.io.File;
@@ -383,6 +384,9 @@
     }
 
     boolean isAppIdle(String packageName, int userId) {
+        if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) {
+            return false;
+        }
         final long lastUsed = getLastPackageAccessTime(packageName, userId);
         return hasPassedIdleDuration(lastUsed);
     }